Skip to content

[Serialization] Always serialize module-defining .swiftinterface, even if SDK-relative. #70817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lib/Frontend/ModuleInterfaceBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,12 @@ std::error_code ExplicitModuleInterfaceBuilder::buildSwiftModuleFromInterface(
!Invocation.getIRGenOptions().ForceLoadSymbolName.empty();
SerializationOpts.UserModuleVersion = FEOpts.UserModuleVersion;
SerializationOpts.AllowableClients = FEOpts.AllowableClients;

// Record any non-SDK module interface files for the debug info.
StringRef SDKPath = Instance.getASTContext().SearchPathOpts.getSDKPath();
if (!getRelativeDepPath(InPath, SDKPath))

auto SDKRelativePath = getRelativeDepPath(InPath, SDKPath);
if (SDKRelativePath.has_value())
SerializationOpts.ModuleInterface = SDKRelativePath.value();
else
SerializationOpts.ModuleInterface = InPath;

SerializationOpts.SDKName = Instance.getASTContext().LangOpts.SDKName;
Expand Down
15 changes: 15 additions & 0 deletions lib/Serialization/ModuleFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ static bool isTargetTooNew(const llvm::Triple &moduleTarget,
return ctxTarget.isOSVersionLT(moduleTarget);
}

std::string ModuleFile::resolveModuleDefiningFilename(const ASTContext &ctx) {
if (!Core->ModuleInterfacePath.empty()) {
std::string interfacePath = Core->ModuleInterfacePath.str();
if (llvm::sys::path::is_relative(interfacePath)) {
SmallString<128> absoluteInterfacePath(ctx.SearchPathOpts.getSDKPath());
llvm::sys::path::append(absoluteInterfacePath, interfacePath);
return absoluteInterfacePath.str().str();
} else
return interfacePath;
} else
return getModuleLoadedFilename().str();
}

namespace swift {
namespace serialization {
bool areCompatible(const llvm::Triple &moduleTarget,
Expand Down Expand Up @@ -257,6 +270,8 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc,
}

ASTContext &ctx = getContext();
// Resolve potentially-SDK-relative module-defining .swiftinterface path
ResolvedModuleDefiningFilename = resolveModuleDefiningFilename(ctx);

llvm::Triple moduleTarget(llvm::Triple::normalize(Core->TargetTriple));
if (!areCompatible(moduleTarget, ctx.LangOpts.Target)) {
Expand Down
11 changes: 11 additions & 0 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class ModuleFile
/// The module that this module is an overlay of, if any.
ModuleDecl *UnderlyingModule = nullptr;

/// Once this module file has been associated with the AST node representing
/// it, resolve the potentially-SDK-relative module-defining `.swiftinterface`
/// path to an absolute path.
llvm::Optional<std::string> ResolvedModuleDefiningFilename;

/// The cursor used to lazily load things from the file.
llvm::BitstreamCursor DeclTypeCursor;

Expand Down Expand Up @@ -280,6 +285,10 @@ class ModuleFile
ArrayRef<ProtocolConformanceID>
claimLazyConformanceLoaderToken(uint64_t token);

/// If the module-defining `.swiftinterface` file is an SDK-relative path,
/// resolve it to be absolute to the context's SDK.
std::string resolveModuleDefiningFilename(const ASTContext &ctx);

/// Represents an identifier that may or may not have been deserialized yet.
///
/// If \c Ident is empty, the identifier has not been loaded yet.
Expand Down Expand Up @@ -849,6 +858,8 @@ class ModuleFile
void getDisplayDecls(SmallVectorImpl<Decl*> &results, bool recursive = false);

StringRef getModuleFilename() const {
if (ResolvedModuleDefiningFilename)
return ResolvedModuleDefiningFilename.value();
if (!Core->ModuleInterfacePath.empty())
return Core->ModuleInterfacePath;
return getModuleLoadedFilename();
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 833; // global_addr with dependency token
const uint16_t SWIFTMODULE_VERSION_MINOR = 834; // relative paths to module-defining .swiftinterface files

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down
27 changes: 27 additions & 0 deletions test/Serialization/module_defining_interface.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/inputs)
// RUN: %empty-directory(%t/test-sdk)
// RUN: %empty-directory(%t/test-sdk/usr/lib/swift)
// RUN: cp -r %platform-module-dir/Swift.swiftmodule %t/test-sdk/usr/lib/swift/Swift.swiftmodule

// RUN: %empty-directory(%t/test-sdk/usr/lib/Foo.swiftmodule)
// RUN: split-file %s %t

// --- Verify that a non-SDK module gets its absolute path serialized into the binary '.swiftmodule'
// RUN: %target-swift-frontend -compile-module-from-interface -module-name Foo %t/modules/Foo.swiftinterface -o %t/inputs/FreestandingFoo.swiftmodule
// RUN: llvm-bcanalyzer -dump %t/inputs/FreestandingFoo.swiftmodule > %t/Foo.freestanding.moduledump.txt
// RUN: cat %t/Foo.freestanding.moduledump.txt | %FileCheck %s -check-prefix CHECK-FREESTANDING-FOO

// --- Verify that an SDK module gets its SDK-relative path serialized into the binary '.swiftmodule'
// RUN: cp %t/modules/Foo.swiftinterface %t/test-sdk/usr/lib/Foo.swiftmodule
// RUN: %target-swift-frontend(mock-sdk: -sdk %t/test-sdk) -compile-module-from-interface -module-name Foo %t/test-sdk/usr/lib/Foo.swiftmodule/Foo.swiftinterface -o %t/inputs/Foo.swiftmodule
// RUN: llvm-bcanalyzer -dump %t/inputs/Foo.swiftmodule > %t/Foo.sdk.moduledump.txt
// RUN: cat %t/Foo.sdk.moduledump.txt | %FileCheck %s -check-prefix CHECK-SDK-FOO

// CHECK-FREESTANDING-FOO: <MODULE_INTERFACE_PATH abbrevid={{[0-9]+}}/> blob data = '{{.*}}{{/|\\}}modules{{/|\\}}Foo.swiftinterface'
// CHECK-SDK-FOO: <MODULE_INTERFACE_PATH abbrevid={{[0-9]+}}/> blob data = 'usr/lib/Foo.swiftmodule/Foo.swiftinterface'

//--- modules/Foo.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Foo
public func foo()
47 changes: 47 additions & 0 deletions test/Serialization/module_defining_interface_client.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/inputs)
// RUN: %empty-directory(%t/test-sdk)
// RUN: %empty-directory(%t/test-sdk/usr/lib/swift)
// RUN: %empty-directory(%t/test-sdk/usr/lib/Foo.swiftmodule)
// RUN: %empty-directory(%t/test-sdk/usr/lib/Bar.swiftmodule)
// RUN: %empty-directory(%t/test-sdk/usr/lib/_Foo_Bar.swiftmodule)
// RUN: %empty-directory(%t/test-sdk/usr/lib/Foo.swiftcrossimport)
// RUN: cp -r %platform-module-dir/Swift.swiftmodule %t/test-sdk/usr/lib/swift/Swift.swiftmodule

// RUN: split-file %s %t

// --- Precompile interfaces from the "SDK" into binary modules distributed elsewhere
// RUN: %target-swift-frontend(mock-sdk: -sdk %t/test-sdk) -compile-module-from-interface -module-name Foo %t/test-sdk/usr/lib/Foo.swiftmodule/Foo.swiftinterface -o %t/inputs/Foo.swiftmodule
// RUN: %target-swift-frontend(mock-sdk: -sdk %t/test-sdk) -compile-module-from-interface -module-name Bar %t/test-sdk/usr/lib/Bar.swiftmodule/Bar.swiftinterface -o %t/inputs/Bar.swiftmodule
// RUN: %target-swift-frontend(mock-sdk: -sdk %t/test-sdk) -compile-module-from-interface -module-name _Foo_Bar %t/test-sdk/usr/lib/_Foo_Bar.swiftmodule/_Foo_Bar.swiftinterface -o %t/inputs/_Foo_Bar.swiftmodule

// --- Verify that the client is able to resolve the cross-import overlay from the defining interface SDK location
// RUN: %target-swift-frontend(mock-sdk: -sdk %t/test-sdk) -typecheck %t/Test.swift -enable-cross-import-overlays -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t/inputs -Rmodule-loading &> %t/module_remarks.txt
// RUN: cat %t/module_remarks.txt | %FileCheck %s
// CHECK: remark: loaded module '_Foo_Bar'

//--- test-sdk/usr/lib/Foo.swiftmodule/Foo.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Foo
public func foo()

//--- test-sdk/usr/lib/Bar.swiftmodule/Bar.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Bar
public func bar()

//--- test-sdk/usr/lib/_Foo_Bar.swiftmodule/_Foo_Bar.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name _Foo_Bar
public func foo_bar()

//--- test-sdk/usr/lib/Foo.swiftcrossimport/Bar.swiftoverlay
---
version: 1
modules:
- name: _Foo_Bar

//--- Test.swift
import Foo
import Bar
public func baz() { foo_bar() }