Skip to content

[Frontend/AST] Add -interface-compiler-version option to frontend/modules #77216

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 6 commits into from
Oct 29, 2024
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
6 changes: 6 additions & 0 deletions include/swift/AST/FileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
return {};
}

/// Returns the version of the Swift compiler used to create generate
/// .swiftinterface file if this file is produced from one.
virtual llvm::VersionTuple getSwiftInterfaceCompilerVersion() const {
return {};
}

SWIFT_DEBUG_DUMPER(dumpDisplayDecls());
SWIFT_DEBUG_DUMPER(dumpTopLevelDecls());

Expand Down
19 changes: 16 additions & 3 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ class ModuleDecl

mutable Identifier PublicModuleName;

/// Indicates a version of the Swift compiler used to generate
/// .swiftinterface file that this module was produced from (if any).
mutable llvm::VersionTuple InterfaceCompilerVersion;

public:
/// Produces the components of a given module's full name in reverse order.
///
Expand Down Expand Up @@ -518,11 +522,20 @@ class ModuleDecl
PublicModuleName = name;
}

/// See \c InterfaceCompilerVersion
llvm::VersionTuple getSwiftInterfaceCompilerVersion() const {
return InterfaceCompilerVersion;
}

void setSwiftInterfaceCompilerVersion(llvm::VersionTuple version) {
InterfaceCompilerVersion = version;
}

/// Retrieve the actual module name of an alias used for this module (if any).
///
/// For example, if '-module-alias Foo=Bar' is passed in when building the main module,
/// and this module is (a) not the main module and (b) is named Foo, then it returns
/// the real (physically on-disk) module name Bar.
/// For example, if '-module-alias Foo=Bar' is passed in when building the
/// main module, and this module is (a) not the main module and (b) is named
/// Foo, then it returns the real (physically on-disk) module name Bar.
///
/// If no module aliasing is set, it will return getName(), i.e. Foo.
Identifier getRealName() const;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Basic/Version.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ StringRef getCurrentCompilerChannel();
/// users.
unsigned getUpcomingCxxInteropCompatVersion();

/// Retrieves the version of the running compiler. It could be a tag or
/// a "development" version that only has major/minor.
std::string getCompilerVersion();

} // end namespace version
} // end namespace swift

Expand Down
4 changes: 4 additions & 0 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ class FrontendOptions {
/// User-defined module version number.
llvm::VersionTuple UserModuleVersion;

/// The Swift compiler version number that would be used to synthesize
/// swiftinterface files and subsequently their swiftmodules.
llvm::VersionTuple SwiftInterfaceCompilerVersion;

/// A set of modules allowed to import this module.
std::set<std::string> AllowableClients;

Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,11 @@ def package_description_version: Separate<["-"], "package-description-version">,
HelpText<"The version number to be applied on the input for the PackageDescription availability kind">,
MetaVarName<"<vers>">;

def swiftinterface_compiler_version : Separate<["-"], "interface-compiler-version">,
Flags<[FrontendOption, HelpHidden]>,
HelpText<"The version of the Swift compiler used to generate a .swiftinterface file">,
MetaVarName<"<intcvers>">;

def tools_directory : Separate<["-"], "tools-directory">,
Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild,
ArgumentIsPath]>,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,8 @@ class SerializedASTFile final : public LoadedFile {

virtual StringRef getPublicModuleName() const override;

virtual llvm::VersionTuple getSwiftInterfaceCompilerVersion() const override;

ValueDecl *getMainDecl() const override;

bool hasEntryPoint() const override;
Expand Down
11 changes: 11 additions & 0 deletions include/swift/Serialization/Validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class ExtendedValidationInfo {
StringRef ExportAsName;
StringRef PublicModuleName;
CXXStdlibKind CXXStdlib;
llvm::VersionTuple SwiftInterfaceCompilerVersion;
struct {
unsigned ArePrivateImportsEnabled : 1;
unsigned IsSIB : 1;
Expand Down Expand Up @@ -250,6 +251,16 @@ class ExtendedValidationInfo {

CXXStdlibKind getCXXStdlibKind() const { return CXXStdlib; }
void setCXXStdlibKind(CXXStdlibKind kind) { CXXStdlib = kind; }

llvm::VersionTuple getSwiftInterfaceCompilerVersion() const {
return SwiftInterfaceCompilerVersion;
}
void setSwiftInterfaceCompilerVersion(StringRef version) {
llvm::VersionTuple compilerVersion;
if (compilerVersion.tryParse(version))
return;
SwiftInterfaceCompilerVersion = compilerVersion;
}
};

struct SearchPath {
Expand Down
13 changes: 13 additions & 0 deletions lib/Basic/Version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,5 +339,18 @@ unsigned getUpcomingCxxInteropCompatVersion() {
return SWIFT_VERSION_MAJOR + 1;
}

std::string getCompilerVersion() {
std::string buf;
llvm::raw_string_ostream OS(buf);

#if defined(SWIFT_COMPILER_VERSION)
OS << SWIFT_COMPILER_VERSION;
#else
OS << SWIFT_VERSION_STRING;
#endif

return OS.str();
}

} // end namespace version
} // end namespace swift
7 changes: 7 additions & 0 deletions lib/Frontend/ArgsToFrontendOptionsConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,13 @@ bool ArgsToFrontendOptionsConverter::convert(
if (const Arg *A = Args.getLastArg(OPT_public_module_name))
Opts.PublicModuleName = A->getValue();

if (auto A = Args.getLastArg(OPT_swiftinterface_compiler_version)) {
if (Opts.SwiftInterfaceCompilerVersion.tryParse(A->getValue())) {
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
A->getAsString(Args), A->getValue());
}
}

// This must be called after computing module name, module abi name,
// and module link name. If computing module aliases is unsuccessful,
// return early.
Expand Down
5 changes: 5 additions & 0 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,11 @@ ModuleDecl *CompilerInstance::getMainModule() const {
if (Invocation.getSILOptions().EnableSerializePackage)
MainModule->setSerializePackageEnabled();

if (auto compilerVersion =
Invocation.getFrontendOptions().SwiftInterfaceCompilerVersion) {
MainModule->setSwiftInterfaceCompilerVersion(compilerVersion);
}

// Register the main module with the AST context.
Context->addLoadedModule(MainModule);
Context->MainModule = MainModule;
Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/ModuleInterfaceSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ static void printToolVersionAndFlagsComment(raw_ostream &out,
!Opts.PackageFlags.IgnorableFlags.empty())
ignorableFlags.push_back(Opts.PackageFlags.IgnorableFlags);

ignorableFlags.push_back("-interface-compiler-version");
ignorableFlags.push_back(version::getCompilerVersion());

if (!ignorableFlags.empty()) {
out << "// " SWIFT_MODULE_FLAGS_IGNORABLE_KEY ": ";
llvm::interleave(
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1409,3 +1409,7 @@ StringRef SerializedASTFile::getExportedModuleName() const {
StringRef SerializedASTFile::getPublicModuleName() const {
return File.getPublicModuleName();
}

llvm::VersionTuple SerializedASTFile::getSwiftInterfaceCompilerVersion() const {
return File.getSwiftInterfaceCompilerVersion();
}
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,10 @@ class ModuleFile
return Core->UserModuleVersion;
}

llvm::VersionTuple getSwiftInterfaceCompilerVersion() const {
return Core->SwiftInterfaceCompilerVersion;
}

ArrayRef<StringRef> getAllowableClientNames() const {
return Core->AllowableClientNames;
}
Expand Down
5 changes: 5 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
case options_block::PUBLIC_MODULE_NAME:
extendedInfo.setPublicModuleName(blobData);
break;
case options_block::SWIFT_INTERFACE_COMPILER_VERSION:
extendedInfo.setSwiftInterfaceCompilerVersion(blobData);
break;
default:
// Unknown options record, possibly for use by a future version of the
// module format.
Expand Down Expand Up @@ -1496,6 +1499,8 @@ ModuleFileSharedCore::ModuleFileSharedCore(
ModulePackageName = extInfo.getModulePackageName();
ModuleExportAsName = extInfo.getExportAsName();
PublicModuleName = extInfo.getPublicModuleName();
SwiftInterfaceCompilerVersion =
extInfo.getSwiftInterfaceCompilerVersion();

hasValidControlBlock = true;
break;
Expand Down
5 changes: 5 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class ModuleFileSharedCore {
/// Name to use in public facing diagnostics and documentation.
StringRef PublicModuleName;

/// The version of the Swift compiler used to produce swiftinterface
/// this module is based on. This is the most precise version possible
/// - a compiler tag or version if this is a development compiler.
llvm::VersionTuple SwiftInterfaceCompilerVersion;

/// \c true if this module has incremental dependency information.
bool HasIncrementalInfo = false;

Expand Down
8 changes: 7 additions & 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 = 897; // Builtin.FixedArray
const uint16_t SWIFTMODULE_VERSION_MINOR = 898; // interface-compiler-version

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -966,6 +966,7 @@ namespace options_block {
SERIALIZE_PACKAGE_ENABLED,
CXX_STDLIB_KIND,
PUBLIC_MODULE_NAME,
SWIFT_INTERFACE_COMPILER_VERSION,
};

using SDKPathLayout = BCRecordLayout<
Expand Down Expand Up @@ -1066,6 +1067,11 @@ namespace options_block {
PUBLIC_MODULE_NAME,
BCBlob
>;

using SwiftInterfaceCompilerVersionLayout = BCRecordLayout<
SWIFT_INTERFACE_COMPILER_VERSION,
BCBlob // version tuple
>;
}

/// The record types within the input block.
Expand Down
8 changes: 8 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,7 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(options_block, SERIALIZE_PACKAGE_ENABLED);
BLOCK_RECORD(options_block, CXX_STDLIB_KIND);
BLOCK_RECORD(options_block, PUBLIC_MODULE_NAME);
BLOCK_RECORD(options_block, SWIFT_INTERFACE_COMPILER_VERSION);

BLOCK(INPUT_BLOCK);
BLOCK_RECORD(input_block, IMPORTED_MODULE);
Expand Down Expand Up @@ -1139,6 +1140,13 @@ void Serializer::writeHeader() {
PublicModuleName.emit(ScratchRecord, publicModuleName.str());
}

llvm::VersionTuple compilerVersion =
M->getSwiftInterfaceCompilerVersion();
if (compilerVersion) {
options_block::SwiftInterfaceCompilerVersionLayout Version(Out);
Version.emit(ScratchRecord, compilerVersion.getAsString());
}

if (M->isConcurrencyChecked()) {
options_block::IsConcurrencyCheckedLayout IsConcurrencyChecked(Out);
IsConcurrencyChecked.emit(ScratchRecord);
Expand Down
2 changes: 2 additions & 0 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
M.setPackageName(Ctx.getIdentifier(loadedModuleFile->getModulePackageName()));
}
M.setUserModuleVersion(loadedModuleFile->getUserModuleVersion());
M.setSwiftInterfaceCompilerVersion(
loadedModuleFile->getSwiftInterfaceCompilerVersion());
for (auto name: loadedModuleFile->getAllowableClientNames()) {
M.addAllowableClientName(Ctx.getIdentifier(name));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
// RUN: not %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/modulecache -emit-module -o %t/TestModule.swiftmodule -module-name TestModule %s >%t/err.txt 2>&1
// RUN: %{python} %S/Inputs/check-is-old.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule
// RUN: %FileCheck %s -check-prefix=CHECK-ERROR <%t/err.txt
// CHECK-ERROR: LeafModule.swiftinterface:7:8: error: no such module 'NotAModule'
// CHECK-ERROR: OtherModule.swiftinterface:4:8: error: failed to build module 'LeafModule' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug
// CHECK-ERROR: LeafModule.swiftinterface:8:8: error: no such module 'NotAModule'
// CHECK-ERROR: OtherModule.swiftinterface:5:8: error: failed to build module 'LeafModule' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug
// CHECK-ERROR: module-cache-diagnostics.swift:{{[0-9]+}}:8: error: failed to build module 'OtherModule' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug
//
//
Expand All @@ -85,8 +85,8 @@
// RUN: not %target-swift-frontend -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -I %t -module-cache-path %t/modulecache -emit-module -o %t/TestModule.swiftmodule -module-name TestModule %s >%t/err-inline.txt 2>&1
// RUN: %{python} %S/Inputs/check-is-old.py %t/modulecache/OtherModule-*.swiftmodule %t/modulecache/LeafModule-*.swiftmodule
// RUN: %FileCheck %s -check-prefix=CHECK-ERROR-INLINE <%t/err-inline.txt
// CHECK-ERROR-INLINE: LeafModule.swiftinterface:6:33: error: cannot find 'unresolved' in scope
// CHECK-ERROR-INLINE: OtherModule.swiftinterface:4:8: error: failed to build module 'LeafModule' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug
// CHECK-ERROR-INLINE: LeafModule.swiftinterface:7:33: error: cannot find 'unresolved' in scope
// CHECK-ERROR-INLINE: OtherModule.swiftinterface:5:8: error: failed to build module 'LeafModule' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug
// CHECK-ERROR-INLINE: module-cache-diagnostics.swift:{{[0-9]+}}:8: error: failed to build module 'OtherModule' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug
//
//
Expand Down
36 changes: 36 additions & 0 deletions test/ModuleInterface/swiftinterface-compiler-version-option.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %empty-directory(%t)

/// Build the libraries.
// RUN: %target-swift-frontend %s \
// RUN: -module-name Lib \
// RUN: -emit-module-path %t/Lib.swiftmodule \
// RUN: -emit-module-interface-path %t/Lib.swiftinterface \
// RUN: -enable-library-evolution \
// RUN: -swift-version 6

// RUN: %target-swift-typecheck-module-from-interface(%t/Lib.swiftinterface)

/// Check option in swiftinterface
// RUN: cat %t/Lib.swiftinterface | %FileCheck --check-prefix=CHECK-OPTION %s
// CHECK-OPTION: swift-module-flags-ignorable:
// CHECK-SAME-OPTION: -swift-compiler-version {{.*}}

/// Check option in swiftmodule
// RUN: llvm-bcanalyzer --dump %t/Lib.swiftmodule | %FileCheck --check-prefix=CHECK-MODULE-OPTION %s
// CHECK-MODULE-OPTION: <OPTIONS_BLOCK
// CHECK-NOT-MODULE-OPTION: <SWIFT_INTERFACE_COMPILER_VERSION abbrevid={{.*}}/> blob data = '{{.*}}'
// CHECK-MODULE-OPTION: </OPTIONS_BLOCK>

// Drop and rebuilt swiftmodule to make sure that the version is inferred from the interface file.
// RUN: rm %t/Lib.swiftmodule
// RUN: %target-swift-frontend -compile-module-from-interface %t/Lib.swiftinterface -o %t/Lib.swiftmodule -module-name Lib

/// Check option in swiftmodule
// RUN: llvm-bcanalyzer --dump %t/Lib.swiftmodule | %FileCheck --check-prefix=CHECK-REBUILT-MODULE-OPTION %s
// CHECK-REBUILT-MODULE-OPTION: <OPTIONS_BLOCK
// CHECK-REBUILT-MODULE-OPTION: <SWIFT_INTERFACE_COMPILER_VERSION abbrevid={{.*}}/> blob data = '{{.*}}'
// CHECK-REBUILT-MODULE-OPTION: </OPTIONS_BLOCK>

public struct S {
public var test: Int = 42
}