Skip to content

Support driver flag -enable-deterministic-check #1842

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
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
9 changes: 9 additions & 0 deletions Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,15 @@ extension Driver {
}
}

if parsedOptions.contains(.enableDeterministicCheck),
isFrontendArgSupported(.enableDeterministicCheck) {
commandLine.appendFlag(.enableDeterministicCheck)
commandLine.appendFlag(.alwaysCompileOutputFiles)
if enableCaching {
commandLine.appendFlag(.cacheDisableReplay)
}
}

// Pass along -no-verify-emitted-module-interface only if it's effective.
// Assume verification by default as we want to know only when the user skips
// the verification.
Expand Down
6 changes: 4 additions & 2 deletions Sources/SwiftOptions/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ extension Option {
public static let enableDeserializationRecovery: Option = Option("-enable-deserialization-recovery", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Attempt to recover from missing xrefs (etc) in swiftmodules")
public static let enableDeserializationSafety: Option = Option("-enable-deserialization-safety", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Avoid reading potentially unsafe decls in swiftmodules")
public static let enableDestroyHoisting: Option = Option("-enable-destroy-hoisting=", .joined, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "true|false", helpText: "Whether to enable destroy hoisting")
public static let enableDeterministicCheck: Option = Option("-enable-deterministic-check", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Check compiler output determinism by running it twice")
public static let enableDeterministicCheck: Option = Option("-enable-deterministic-check", .flag, attributes: [.frontend, .doesNotAffectIncrementalBuild, .cacheInvariant], helpText: "Check compiler output determinism by running it twice")
public static let enableDynamicReplacementChaining: Option = Option("-enable-dynamic-replacement-chaining", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable chaining of dynamic replacements")
public static let enableEmitGenericClassRoTList: Option = Option("-enable-emit-generic-class-ro_t-list", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable emission of a section with references to class_ro_t of generic class patterns")
public static let enableEmitTypeMallocForCoroFrame: Option = Option("-enable-emit-type-malloc-for-coro-frame", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable emitting typed malloc for coroutine frame allocation")
Expand Down Expand Up @@ -564,6 +564,7 @@ extension Option {
public static let forcePublicLinkage: Option = Option("-force-public-linkage", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Force public linkage for private symbols. Used by LLDB.")
public static let forceSingleFrontendInvocation: Option = Option("-force-single-frontend-invocation", .flag, alias: Option.wholeModuleOptimization, attributes: [.helpHidden, .frontend, .noInteractive])
public static let forceStructTypeLayouts: Option = Option("-force-struct-type-layouts", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Force type layout based lowering for structs")
public static let formalCxxInteroperabilityMode: Option = Option("-formal-cxx-interoperability-mode=", .joined, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "<cxx-interop-version>|off", helpText: "What version of C++ interoperability a textual interface was originally generated with")
public static let framework: Option = Option("-framework", .separate, attributes: [.frontend, .doesNotAffectIncrementalBuild], helpText: "Specifies a framework which should be linked against", group: .linkerOption)
public static let frontendParseableOutput: Option = Option("-frontend-parseable-output", .flag, attributes: [.frontend, .noDriver, .cacheInvariant], helpText: "Emit textual output in a parseable format")
public static let Fsystem: Option = Option("-Fsystem", .separate, attributes: [.frontend, .synthesizeInterface, .argumentIsPath], helpText: "Add directory to system framework search path")
Expand Down Expand Up @@ -848,7 +849,7 @@ extension Option {
public static let staticExecutable: Option = Option("-static-executable", .flag, helpText: "Statically link the executable")
public static let staticStdlib: Option = Option("-static-stdlib", .flag, attributes: [.doesNotAffectIncrementalBuild], helpText: "Statically link the Swift standard library")
public static let `static`: Option = Option("-static", .flag, attributes: [.frontend, .noInteractive, .moduleInterface], helpText: "Make this module statically linkable and make the output of -emit-library a static library.")
public static let statsOutputDir: Option = Option("-stats-output-dir", .separate, attributes: [.helpHidden, .frontend, .argumentIsPath], helpText: "Directory to write unified compilation-statistics files to")
public static let statsOutputDir: Option = Option("-stats-output-dir", .separate, attributes: [.helpHidden, .frontend, .argumentIsPath, .cacheInvariant], helpText: "Directory to write unified compilation-statistics files to")
public static let strictConcurrency: Option = Option("-strict-concurrency=", .joined, attributes: [.frontend, .doesNotAffectIncrementalBuild], helpText: "Specify the how strict concurrency checking will be. The value may be 'minimal' (most 'Sendable' checking is disabled), 'targeted' ('Sendable' checking is enabled in code that uses the concurrency model, or 'complete' ('Sendable' and other checking is enabled for all code in the module)")
public static let strictImplicitModuleContext: Option = Option("-strict-implicit-module-context", .flag, attributes: [.helpHidden, .frontend], helpText: "Enable the strict forwarding of compilation context to downstream implicit module dependencies")
public static let strictMemorySafety: Option = Option("-strict-memory-safety", .flag, attributes: [.frontend, .synthesizeInterface], helpText: "Enable strict memory safety checking")
Expand Down Expand Up @@ -1508,6 +1509,7 @@ extension Option {
Option.forcePublicLinkage,
Option.forceSingleFrontendInvocation,
Option.forceStructTypeLayouts,
Option.formalCxxInteroperabilityMode,
Option.framework,
Option.frontendParseableOutput,
Option.Fsystem,
Expand Down
44 changes: 44 additions & 0 deletions Tests/SwiftDriverTests/CachingBuildTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,50 @@ final class CachingBuildTests: XCTestCase {
}
}

func testDeterministicCheck() throws {
try withTemporaryDirectory { path in
try localFileSystem.changeCurrentWorkingDirectory(to: path)
let moduleCachePath = path.appending(component: "ModuleCache")
let casPath = path.appending(component: "cas")
try localFileSystem.createDirectory(moduleCachePath)
let main = path.appending(component: "testCachingBuild.swift")
let mainFileContent = "import C;"
try localFileSystem.writeFileContents(main) {
$0.send(mainFileContent)
}
let cHeadersPath: AbsolutePath =
try testInputsPath.appending(component: "ExplicitModuleBuilds")
.appending(component: "CHeaders")
let swiftModuleInterfacesPath: AbsolutePath =
try testInputsPath.appending(component: "ExplicitModuleBuilds")
.appending(component: "Swift")
let sdkArgumentsForTesting = (try? Driver.sdkArgumentsForTesting()) ?? []
let bridgingHeaderpath: AbsolutePath =
cHeadersPath.appending(component: "Bridging.h")
var driver = try Driver(args: ["swiftc",
"-I", cHeadersPath.nativePathString(escaped: true),
"-I", swiftModuleInterfacesPath.nativePathString(escaped: true),
"-explicit-module-build", "-enable-deterministic-check",
"-module-cache-path", moduleCachePath.nativePathString(escaped: true),
"-cache-compile-job", "-cas-path", casPath.nativePathString(escaped: true),
"-import-objc-header", bridgingHeaderpath.nativePathString(escaped: true),
"-working-directory", path.nativePathString(escaped: true),
main.nativePathString(escaped: true)] + sdkArgumentsForTesting,
interModuleDependencyOracle: dependencyOracle)
let jobs = try driver.planBuild()
jobs.forEach { job in
guard job.kind == .compile else {
return
}
XCTAssertJobInvocationMatches(job,
.flag("-enable-deterministic-check"),
.flag("-always-compile-output-files"),
.flag("-cache-disable-replay"))
}
}

}

func testCASManagement() throws {
try withTemporaryDirectory { path in
let casPath = path.appending(component: "cas")
Expand Down
11 changes: 11 additions & 0 deletions Tests/SwiftDriverTests/SwiftDriverTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7069,6 +7069,17 @@ final class SwiftDriverTests: XCTestCase {
}
}

func testDeterministicCheck() throws {
do {
var driver = try Driver(args: ["swiftc", "-enable-deterministic-check", "foo.swift",
"-import-objc-header", "foo.h", "-enable-bridging-pch"])
let plannedJobs = try driver.planBuild()
// Check bridging header compilation command and main module command.
XCTAssertJobInvocationMatches(plannedJobs[0], .flag("-enable-deterministic-check"), .flag("-always-compile-output-files"))
XCTAssertJobInvocationMatches(plannedJobs[1], .flag("-enable-deterministic-check"), .flag("-always-compile-output-files"))
}
}

func testWarnConcurrency() throws {
do {
var driver = try Driver(args: ["swiftc", "-warn-concurrency", "foo.swift"])
Expand Down