From b44095442feb1b2056daee32a2817a5ab7a33647 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 28 Feb 2023 14:15:28 -0800 Subject: [PATCH] Add Swift compilation flags to enable Clang's validate-per-build-session module behavior Compiler flags added in: https://github.com/apple/swift/pull/63975 Driver portion of rdar://105982120 --- Sources/SwiftDriver/Driver/Driver.swift | 12 +++++++ .../SwiftDriver/Jobs/FrontendJobHelpers.swift | 8 +++++ Sources/SwiftOptions/Options.swift | 8 +++++ Tests/SwiftDriverTests/SwiftDriverTests.swift | 33 +++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 51dc76dca..50fcc857b 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -626,6 +626,7 @@ public struct Driver { workingDirectory: workingDirectory, diagnosticEngine: diagnosticEngine) Self.validateEmitDependencyGraphArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) + Self.validateValidateClangModulesOnceOptions(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateParseableOutputArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateCompilationConditionArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) Self.validateFrameworkSearchPathArgs(&parsedOptions, diagnosticEngine: diagnosticEngine) @@ -2701,6 +2702,17 @@ extension Driver { } } + static func validateValidateClangModulesOnceOptions(_ parsedOptions: inout ParsedOptions, + diagnosticEngine: DiagnosticsEngine) { + // '-validate-clang-modules-once' requires '-clang-build-session-file' + if parsedOptions.hasArgument(.validateClangModulesOnce) && + !parsedOptions.hasArgument(.clangBuildSessionFile) { + diagnosticEngine.emit(.error(Error.optionRequiresAnother(Option.validateClangModulesOnce.spelling, + Option.clangBuildSessionFile.spelling)), + location: nil) + } + } + static func validateEmitDependencyGraphArgs(_ parsedOptions: inout ParsedOptions, diagnosticEngine: DiagnosticsEngine) { // '-print-explicit-dependency-graph' requires '-explicit-module-build' diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index 506495aff..c8820225c 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -263,6 +263,14 @@ extension Driver { commandLine.appendFlag(ver) } + // Pass down -validate-clang-modules-once if we are working with a compiler that + // supports it. + if isFrontendArgSupported(.validateClangModulesOnce), + isFrontendArgSupported(.clangBuildSessionFile) { + try commandLine.appendLast(.validateClangModulesOnce, from: &parsedOptions) + try commandLine.appendLast(.clangBuildSessionFile, from: &parsedOptions) + } + if let workingDirectory = workingDirectory { // Add -Xcc -working-directory before any other -Xcc options to ensure it is // overridden by an explicit -Xcc -working-directory, although having a diff --git a/Sources/SwiftOptions/Options.swift b/Sources/SwiftOptions/Options.swift index c5b6da8b3..9ef16a15a 100644 --- a/Sources/SwiftOptions/Options.swift +++ b/Sources/SwiftOptions/Options.swift @@ -52,6 +52,7 @@ extension Option { public static let candidateModuleFile: Option = Option("-candidate-module-file", .separate, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "", helpText: "Specify Swift module may be ready to use for an interface") public static let checkApiAvailabilityOnly: Option = Option("-check-api-availability-only", .flag, attributes: [.helpHidden, .frontend, .noInteractive], helpText: "Only check the availability of the APIs, ignore function bodies") public static let checkOnoneCompleteness: Option = Option("-check-onone-completeness", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Print errors if the compile OnoneSupport module is missing symbols") + public static let clangBuildSessionFile: Option = Option("-clang-build-session-file", .separate, attributes: [.frontend, .argumentIsPath], helpText: "Use the last modification time of as the underlying Clang build session timestamp") public static let clangHeaderExposeDecls: Option = Option("-clang-header-expose-decls=", .joined, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "all-public|has-expose-attr", helpText: "Which declarations should be exposed in the generated clang header.") public static let clangTarget: Option = Option("-clang-target", .separate, attributes: [.frontend], helpText: "Separately set the target we should use for internal Clang instance") public static let codeCompleteCallPatternHeuristics: Option = Option("-code-complete-call-pattern-heuristics", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use heuristics to guess whether we want call pattern completions") @@ -128,6 +129,7 @@ extension Option { public static let disableClangimporterSourceImport: Option = Option("-disable-clangimporter-source-import", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable ClangImporter and forward all requests straight the DWARF importer.") public static let disableCrossModuleOptimization: Option = Option("-disable-cmo", .flag, attributes: [.helpHidden, .frontend], helpText: "Disable cross-module optimization") public static let disableCollocateMetadataFunctions: Option = Option("-disable-collocate-metadata-functions", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable collocate metadata functions") + public static let disableColocateTypeDescriptors: Option = Option("-disable-colocate-type-descriptors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable colocate type descriptors") public static let disableConcreteTypeMetadataMangledNameAccessors: Option = Option("-disable-concrete-type-metadata-mangled-name-accessors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable concrete type metadata access by mangled name") public static let disableConformanceAvailabilityErrors: Option = Option("-disable-conformance-availability-errors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Diagnose conformance availability violations as warnings") public static let disableConstraintSolverPerformanceHacks: Option = Option("-disable-constraint-solver-performance-hacks", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable all the hacks in the constraint solver") @@ -321,6 +323,7 @@ extension Option { public static let enableBridgingPch: Option = Option("-enable-bridging-pch", .flag, attributes: [.helpHidden], helpText: "Enable automatic generation of bridging PCH files") public static let enableBuiltinModule: Option = Option("-enable-builtin-module", .flag, attributes: [.frontend, .moduleInterface], helpText: "Enables the explicit import of the Builtin module") public static let enableCollocateMetadataFunctions: Option = Option("-enable-collocate-metadata-functions", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable collocate metadata functions") + public static let enableColocateTypeDescriptors: Option = Option("-enable-colocate-type-descriptors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable colocate type descriptors") public static let enableConformanceAvailabilityErrors: Option = Option("-enable-conformance-availability-errors", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Diagnose conformance availability violations as errors") public static let copyPropagationStateEQ: Option = Option("-enable-copy-propagation=", .joined, attributes: [.frontend, .noDriver], metaVar: "true|requested-passes-only|false", helpText: "Whether to enable copy propagation") public static let enableCopyPropagation: Option = Option("-enable-copy-propagation", .flag, attributes: [.frontend, .noDriver], helpText: "Run SIL copy propagation with lexical lifetimes to shorten object lifetimes while preserving variable lifetimes.") @@ -714,6 +717,7 @@ extension Option { public static let useStaticResourceDir: Option = Option("-use-static-resource-dir", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Use resources in the static resource directory") public static let useTabs: Option = Option("-use-tabs", .flag, attributes: [.noInteractive, .noBatch, .indent], helpText: "Use tabs for indentation.", group: .codeFormatting) public static let userModuleVersion: Option = Option("-user-module-version", .separate, attributes: [.frontend], metaVar: "", helpText: "Module version specified from Swift module authors") + public static let validateClangModulesOnce: Option = Option("-validate-clang-modules-once", .flag, attributes: [.frontend], helpText: "Don't verify input files for Clang modules if the module has been successfully validated or loaded during this build session") public static let validateTbdAgainstIrEQ: Option = Option("-validate-tbd-against-ir=", .joined, attributes: [.helpHidden, .frontend, .noDriver], metaVar: "", helpText: "Compare the symbols in the IR against the TBD file that would be generated.") public static let valueRecursionThreshold: Option = Option("-value-recursion-threshold", .separate, attributes: [.helpHidden, .frontend, .doesNotAffectIncrementalBuild], helpText: "Set the maximum depth for direct recursion in value types") public static let verifyAdditionalFile: Option = Option("-verify-additional-file", .separate, attributes: [.frontend, .noDriver], helpText: "Verify diagnostics in this file in addition to source files") @@ -801,6 +805,7 @@ extension Option { Option.candidateModuleFile, Option.checkApiAvailabilityOnly, Option.checkOnoneCompleteness, + Option.clangBuildSessionFile, Option.clangHeaderExposeDecls, Option.clangTarget, Option.codeCompleteCallPatternHeuristics, @@ -877,6 +882,7 @@ extension Option { Option.disableClangimporterSourceImport, Option.disableCrossModuleOptimization, Option.disableCollocateMetadataFunctions, + Option.disableColocateTypeDescriptors, Option.disableConcreteTypeMetadataMangledNameAccessors, Option.disableConformanceAvailabilityErrors, Option.disableConstraintSolverPerformanceHacks, @@ -1070,6 +1076,7 @@ extension Option { Option.enableBridgingPch, Option.enableBuiltinModule, Option.enableCollocateMetadataFunctions, + Option.enableColocateTypeDescriptors, Option.enableConformanceAvailabilityErrors, Option.copyPropagationStateEQ, Option.enableCopyPropagation, @@ -1463,6 +1470,7 @@ extension Option { Option.useStaticResourceDir, Option.useTabs, Option.userModuleVersion, + Option.validateClangModulesOnce, Option.validateTbdAgainstIrEQ, Option.valueRecursionThreshold, Option.verifyAdditionalFile, diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 17fa8a477..a19d13fd8 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -6663,6 +6663,39 @@ final class SwiftDriverTests: XCTestCase { XCTAssertTrue(job.commandLine.contains(.path(.absolute(try driver.toolchain.executableDir.parentDirectory.appending(components: "lib", "swift", "host", "plugins"))))) } + func testClangModuleValidateOnce() throws { + let flagTest = try Driver(args: ["swiftc", "-typecheck", "foo.swift"]) + guard flagTest.isFrontendArgSupported(.clangBuildSessionFile), + flagTest.isFrontendArgSupported(.validateClangModulesOnce) else { + return + } + + do { + var driver = try Driver(args: ["swiftc", "-typecheck", "foo.swift"]) + let jobs = try driver.planBuild().removingAutolinkExtractJobs() + let job = jobs.first! + XCTAssertFalse(job.commandLine.contains(.flag("-validate-clang-modules-once"))) + XCTAssertFalse(job.commandLine.contains(.flag("-clang-build-session-file"))) + } + + do { + try assertDriverDiagnostics(args: ["swiftc", "-validate-clang-modules-once", + "foo.swift"]) { + $1.expect(.error("'-validate-clang-modules-once' cannot be specified if '-clang-build-session-file' is not present")) + } + } + + do { + var driver = try Driver(args: ["swiftc", "-validate-clang-modules-once", + "-clang-build-session-file", "testClangModuleValidateOnce.session", + "foo.swift"]) + let jobs = try driver.planBuild().removingAutolinkExtractJobs() + let job = jobs.first! + XCTAssertTrue(job.commandLine.contains(.flag("-validate-clang-modules-once"))) + XCTAssertTrue(job.commandLine.contains(.flag("-clang-build-session-file"))) + } + } + func testRegistrarLookup() throws { #if os(Windows) let SDKROOT: AbsolutePath = localFileSystem.currentWorkingDirectory!.appending(components: "SDKROOT")