diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index b2f0a5cf0..30ebd7c34 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -243,9 +243,12 @@ public struct Driver { /// The debug information to produce. @_spi(Testing) public let debugInfo: DebugInfo - // The information about the module to produce. + /// The information about the module to produce. @_spi(Testing) public let moduleOutputInfo: ModuleOutputInfo + /// Name of the package containing a target module or file. + @_spi(Testing) public let packageName: String? + /// Info needed to write and maybe read the build record. /// Only present when the driver will be writing the record. /// Only used for reading when compiling incrementally. @@ -637,6 +640,13 @@ public struct Driver { // Compute debug information output. self.debugInfo = Self.computeDebugInfo(&parsedOptions, diagnosticsEngine: diagnosticEngine) + // Validate package name; if package name is nil, it will be checked + // in the frontend during type check on `package` symbols + self.packageName = parsedOptions.getLastArgument(.packageName)?.asSingle + if let packageName = packageName, !packageName.sd_isSwiftIdentifier { + diagnosticsEngine.emit(.error_bad_package_name(packageName)) + } + // Determine the module we're building and whether/how the module file itself will be emitted. self.moduleOutputInfo = try Self.computeModuleInfo( &parsedOptions, compilerOutputType: compilerOutputType, compilerMode: compilerMode, linkerOutputType: linkerOutputType, diff --git a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift index 78cfbe5ee..950261457 100644 --- a/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift +++ b/Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift @@ -311,6 +311,10 @@ extension Driver { commandLine.appendFlags("-module-name", moduleOutputInfo.name) } + if let packageName = packageName { + commandLine.appendFlags("-package-name", packageName) + } + // Enable frontend Parseable-output, if needed. if parsedOptions.contains(.useFrontendParseableOutput) { commandLine.appendFlag("-frontend-parseable-output") diff --git a/Sources/SwiftDriver/Utilities/Diagnostics.swift b/Sources/SwiftDriver/Utilities/Diagnostics.swift index 7ebddc0e5..262e5d355 100644 --- a/Sources/SwiftDriver/Utilities/Diagnostics.swift +++ b/Sources/SwiftDriver/Utilities/Diagnostics.swift @@ -115,6 +115,13 @@ extension Diagnostic.Message { return .error("bad module alias \"\(arg)\"") } + static func error_bad_package_name(_ packageName: String) -> Diagnostic.Message { + if packageName.isEmpty { + return .error("package name is empty; pass a non-empty string or remove \'-package-name\'") + } + return .error("package name \"\(packageName)\" is not a valid identifier") + } + static var error_hermetic_seal_cannot_have_library_evolution: Diagnostic.Message { .error("Cannot use -experimental-hermetic-seal-at-link with -enable-library-evolution") } diff --git a/Sources/SwiftOptions/Options.swift b/Sources/SwiftOptions/Options.swift index 254c64395..f436305ca 100644 --- a/Sources/SwiftOptions/Options.swift +++ b/Sources/SwiftOptions/Options.swift @@ -134,6 +134,7 @@ extension Option { public static let disableCrossImportOverlays: Option = Option("-disable-cross-import-overlays", .flag, attributes: [.frontend, .noDriver], helpText: "Do not automatically import declared cross-import overlays.") public static let disableDebuggerShadowCopies: Option = Option("-disable-debugger-shadow-copies", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable debugger shadow copies of local variables.This option is only useful for testing the compiler.") public static let disableDeserializationRecovery: Option = Option("-disable-deserialization-recovery", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Don't attempt to recover from missing xrefs (etc) in swiftmodules") + public static let disableDeserializationSafety: Option = Option("-disable-deserialization-safety", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Don't avoid reading potentially unsafe decls in swiftmodules") public static let disableDiagnosticPasses: Option = Option("-disable-diagnostic-passes", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Don't run diagnostic passes") public static let disableEmitGenericClassRoTList: Option = Option("-disable-emit-generic-class-ro_t-list", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable emission of a section with references to class_ro_t of generic class patterns") public static let disableExperimentalClangImporterDiagnostics: Option = Option("-disable-experimental-clang-importer-diagnostics", .flag, attributes: [.helpHidden, .frontend, .noDriver, .moduleInterface], helpText: "Disable experimental diagnostics when importing C, C++, and Objective-C libraries") @@ -174,6 +175,7 @@ extension Option { public static let disableReadonlyStaticObjects: Option = Option("-disable-readonly-static-objects", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Avoid allocating static objects in a read-only data section") public static let disableReflectionMetadata: Option = Option("-disable-reflection-metadata", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable emission of reflection metadata for nominal types") public static let disableReflectionNames: Option = Option("-disable-reflection-names", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable emission of names of stored properties and enum cases inreflection metadata") + public static let disableRelativeProtocolWitnessTables: Option = Option("-disable-relative-protocol-witness-tables", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable relative protocol witness tables") public static let disableRemoveDeprecatedCheck: Option = Option("-disable-remove-deprecated-check", .flag, attributes: [.noDriver], helpText: "Skip diagnosing removal of deprecated symbols") public static let disableRemoveDeprecatedCheck_: Option = Option("--disable-remove-deprecated-check", .flag, alias: Option.disableRemoveDeprecatedCheck, attributes: [.noDriver], helpText: "Skip diagnosing removal of deprecated symbols") public static let disableRequirementMachineConcreteContraction: Option = Option("-disable-requirement-machine-concrete-contraction", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Disable preprocessing pass to eliminate conformance requirements on generic parameters which are made concrete") @@ -322,6 +324,7 @@ extension Option { public static let enableCrossImportOverlays: Option = Option("-enable-cross-import-overlays", .flag, attributes: [.frontend, .noDriver], helpText: "Automatically import declared cross-import overlays.") public static let EnbaleDefaultCMO: Option = Option("-enable-default-cmo", .flag, attributes: [.helpHidden, .frontend], helpText: "Perform conservative cross-module optimization") 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 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") @@ -367,6 +370,7 @@ extension Option { public static let enableOperatorDesignatedTypes: Option = Option("-enable-operator-designated-types", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable operator designated types") public static let enableOssaModules: Option = Option("-enable-ossa-modules", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Always serialize SIL in ossa form. If this flag is not passed in, when optimizing ownership will be lowered before serializing SIL") public static let enablePrivateImports: Option = Option("-enable-private-imports", .flag, attributes: [.helpHidden, .frontend, .noInteractive], helpText: "Allows this module's internal and private API to be accessed") + public static let enableRelativeProtocolWitnessTables: Option = Option("-enable-relative-protocol-witness-tables", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable relative protocol witness tables") public static let enableRequirementMachineOpaqueArchetypes: Option = Option("-enable-requirement-machine-opaque-archetypes", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enable more correct opaque archetype support, which is off by default because it might fail to produce a convergent rewrite system") public static let enableResilience: Option = Option("-enable-resilience", .flag, attributes: [.helpHidden, .frontend, .noDriver, .moduleInterface], helpText: "Deprecated, use -enable-library-evolution instead") public static let enableRoundTripDebugTypes: Option = Option("-enable-round-trip-debug-types", .flag, attributes: [.helpHidden, .frontend, .noDriver], helpText: "Enables verification of debug info mangling") @@ -541,6 +545,7 @@ extension Option { public static let O: Option = Option("-O", .flag, attributes: [.frontend, .moduleInterface], helpText: "Compile with optimizations", group: .O) public static let o: Option = Option("-o", .joinedOrSeparate, attributes: [.frontend, .noInteractive, .autolinkExtract, .moduleWrap, .indent, .argumentIsPath], metaVar: "", helpText: "Write output to ") public static let packageDescriptionVersion: Option = Option("-package-description-version", .separate, attributes: [.helpHidden, .frontend, .moduleInterface], metaVar: "", helpText: "The version number to be applied on the input for the PackageDescription availability kind") + public static let packageName: Option = Option("-package-name", .separate, attributes: [.frontend], helpText: "Name of the package the module belongs to") public static let parseAsLibrary: Option = Option("-parse-as-library", .flag, attributes: [.frontend, .noInteractive], helpText: "Parse the input file(s) as libraries, not scripts") public static let parseSil: Option = Option("-parse-sil", .flag, attributes: [.frontend, .noInteractive], helpText: "Parse the input file as SIL code, not Swift source") public static let parseStdlib: Option = Option("-parse-stdlib", .flag, attributes: [.helpHidden, .frontend, .moduleInterface], helpText: "Parse the input file(s) as the Swift standard library") @@ -868,6 +873,7 @@ extension Option { Option.disableCrossImportOverlays, Option.disableDebuggerShadowCopies, Option.disableDeserializationRecovery, + Option.disableDeserializationSafety, Option.disableDiagnosticPasses, Option.disableEmitGenericClassRoTList, Option.disableExperimentalClangImporterDiagnostics, @@ -908,6 +914,7 @@ extension Option { Option.disableReadonlyStaticObjects, Option.disableReflectionMetadata, Option.disableReflectionNames, + Option.disableRelativeProtocolWitnessTables, Option.disableRemoveDeprecatedCheck, Option.disableRemoveDeprecatedCheck_, Option.disableRequirementMachineConcreteContraction, @@ -1056,6 +1063,7 @@ extension Option { Option.enableCrossImportOverlays, Option.EnbaleDefaultCMO, Option.enableDeserializationRecovery, + Option.enableDeserializationSafety, Option.enableDestroyHoisting, Option.enableDynamicReplacementChaining, Option.enableEmitGenericClassRoTList, @@ -1101,6 +1109,7 @@ extension Option { Option.enableOperatorDesignatedTypes, Option.enableOssaModules, Option.enablePrivateImports, + Option.enableRelativeProtocolWitnessTables, Option.enableRequirementMachineOpaqueArchetypes, Option.enableResilience, Option.enableRoundTripDebugTypes, @@ -1275,6 +1284,7 @@ extension Option { Option.O, Option.o, Option.packageDescriptionVersion, + Option.packageName, Option.parseAsLibrary, Option.parseSil, Option.parseStdlib, diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 9bb204bbd..b94699fa9 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -689,6 +689,29 @@ final class SwiftDriverTests: XCTestCase { try assertNoDriverDiagnostics(args: "swiftc", "foo-bar.swift") } + func testPackageNameFlag() throws { + // -package-name mypkg (valid string) + try assertNoDriverDiagnostics(args: "swiftc", "file.swift", "bar.swift", "-module-name", "MyModule", "-package-name", "mypkg", "-emit-module", "-emit-module-path", "../../path/to/MyModule.swiftmodule") { driver in + XCTAssertEqual(driver.packageName, "mypkg") + XCTAssertEqual(driver.moduleOutputInfo.output, .topLevel(try VirtualPath.intern(path: "../../path/to/MyModule.swiftmodule"))) + } + + // -package-name is not passed + try assertNoDriverDiagnostics(args: "swiftc", "file.swift") { driver in + XCTAssertNil(driver.packageName) + XCTAssertEqual(driver.moduleOutputInfo.name, "file") + } + } + + func testPackageNameDiags() throws { + try assertDriverDiagnostics(args: ["swiftc", "file.swift", "-package-name", ""]) { + $1.expect(.error("package name is empty; pass a non-empty string or remove \'-package-name\'")) + } + try assertDriverDiagnostics(args: ["swiftc", "file.swift", "-module-name", "Foo", "-package-name", "123a!@#$"]) { + $1.expect(.error("package name \"123a!@#$\" is not a valid identifier")) + } + } + func testStandardCompileJobs() throws { var driver1 = try Driver(args: ["swiftc", "foo.swift", "bar.swift", "-module-name", "Test"]) let plannedJobs = try driver1.planBuild().removingAutolinkExtractJobs() diff --git a/Tests/SwiftOptionsTests/OptionParsingTests.swift b/Tests/SwiftOptionsTests/OptionParsingTests.swift index b685e1c45..71346857a 100644 --- a/Tests/SwiftOptionsTests/OptionParsingTests.swift +++ b/Tests/SwiftOptionsTests/OptionParsingTests.swift @@ -19,14 +19,14 @@ final class SwiftDriverTests: XCTestCase { // Parse each kind of option let results = try options.parse([ "input1", "-color-diagnostics", "-Ifoo", "-I", "bar spaces", - "-I=wibble", "input2", "-module-name", "main", + "-I=wibble", "input2", "-module-name", "main", "-package-name", "mypkg", "-sanitize=a,b,c", "--", "-foo", "-bar"], for: .batch) #if os(Windows) XCTAssertEqual(results.description, - #"input1 -color-diagnostics -I foo -I "bar spaces" -I=wibble input2 -module-name main -sanitize=a,b,c -- -foo -bar"#) + #"input1 -color-diagnostics -I foo -I "bar spaces" -I=wibble input2 -module-name main -package-name mypkg -sanitize=a,b,c -- -foo -bar"#) #else XCTAssertEqual(results.description, - "input1 -color-diagnostics -I foo -I 'bar spaces' -I=wibble input2 -module-name main -sanitize=a,b,c -- -foo -bar") + "input1 -color-diagnostics -I foo -I 'bar spaces' -I=wibble input2 -module-name main -package-name mypkg -sanitize=a,b,c -- -foo -bar") #endif } @@ -64,6 +64,14 @@ final class SwiftDriverTests: XCTestCase { XCTAssertEqual(error as? OptionParseError, .missingArgument(index: 0, argument: "-module-name")) } + XCTAssertThrowsError(try options.parse(["-package-name"], for: .batch)) { error in + XCTAssertEqual(error as? OptionParseError, .missingArgument(index: 0, argument: "-package-name")) + } + + XCTAssertThrowsError(try options.parse(["-package-name"], for: .interactive)) { error in + XCTAssertEqual(error as? OptionParseError, .missingArgument(index: 0, argument: "-package-name")) + } + XCTAssertThrowsError(try options.parse(["-o"], for: .interactive)) { error in XCTAssertEqual(error as? OptionParseError, .unsupportedOption(index: 0, argument: "-o", option: .o, currentDriverKind: .interactive)) }