diff --git a/Documentation/Porting.md b/Documentation/Porting.md index 4773e2823..365551d4c 100644 --- a/Documentation/Porting.md +++ b/Documentation/Porting.md @@ -193,7 +193,7 @@ to load that information: ``` You will also need to update the `makeTestContentRecordDecl()` function in the -`TestingMacros` target to emit the correct `@_section` attribute for your +`TestingMacros` target to emit the correct `@section` attribute for your platform. If your platform uses the ELF image format and supports the `dl_iterate_phdr()` function, add it to the existing `#elseif os(Linux) || ...` case. Otherwise, add a new case for your platform: @@ -203,7 +203,7 @@ case. Otherwise, add a new case for your platform: +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift // ... + #elseif os(Classic) -+ @_section(".rsrc,swft,__swift5_tests") ++ @section(".rsrc,swft,__swift5_tests") #else @__testing(warning: "Platform-specific implementation missing: test content section name unavailable") #endif @@ -214,6 +214,11 @@ directly into test authors' test targets, so you will not be able to use compiler conditionals defined in the Swift Testing package (including those that start with `"SWT_"`). +> [!NOTE] +> We are not using `objectFormat()` yet to maintain compatibility with the Swift +> 6.2 toolchain. We will migrate to `objectFormat()` when we drop Swift 6.2 +> toolchain support (presumably after Swift 6.3 ships). + ## Runtime test discovery with static linkage If your platform does not support dynamic linking and loading, you will need to diff --git a/Package.swift b/Package.swift index a82241527..19ebefc4c 100644 --- a/Package.swift +++ b/Package.swift @@ -385,11 +385,6 @@ extension Array where Element == PackageDescription.SwiftSetting { .enableUpcomingFeature("MemberImportVisibility"), - // This setting is enabled in the package, but not in the toolchain build - // (via CMake). Enabling it is dependent on acceptance of the @section - // proposal via Swift Evolution. - .enableExperimentalFeature("SymbolLinkageMarkers"), - .enableUpcomingFeature("InferIsolatedConformances"), // When building as a package, the macro plugin always builds as an diff --git a/Sources/TestingMacros/ConditionMacro.swift b/Sources/TestingMacros/ConditionMacro.swift index 6ba8ff124..a7697c97b 100644 --- a/Sources/TestingMacros/ConditionMacro.swift +++ b/Sources/TestingMacros/ConditionMacro.swift @@ -13,10 +13,6 @@ public import SwiftSyntax import SwiftSyntaxBuilder public import SwiftSyntaxMacros -#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY -#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand #expect(processExitsWith:)") -#endif - /// A protocol containing the common implementation for the expansions of the /// `#expect()` and `#require()` macros. /// @@ -496,7 +492,7 @@ extension ExitTestConditionMacro { // Create another local type for legacy test discovery. var recordDecl: DeclSyntax? -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(<6.3) let legacyEnumName = context.makeUniqueName("__🟡$") recordDecl = """ enum \(legacyEnumName): Testing.__TestContentRecordContainer { @@ -511,7 +507,7 @@ extension ExitTestConditionMacro { """ @available(*, deprecated, message: "This type is an implementation detail of the testing library. Do not use it directly.") enum \(enumName) { - private nonisolated static let accessor: Testing.__TestContentRecordAccessor = { outValue, type, hint, _ in + @c private nonisolated static func accessor(_ outValue: UnsafeMutableRawPointer, _ type: UnsafeRawPointer, _ hint: UnsafeRawPointer?, _: UInt) -> CBool { Testing.ExitTest.__store( \(idExpr), \(bodyThunkName), diff --git a/Sources/TestingMacros/SuiteDeclarationMacro.swift b/Sources/TestingMacros/SuiteDeclarationMacro.swift index 4bee4c30f..73eb09a76 100644 --- a/Sources/TestingMacros/SuiteDeclarationMacro.swift +++ b/Sources/TestingMacros/SuiteDeclarationMacro.swift @@ -13,10 +13,6 @@ public import SwiftSyntax import SwiftSyntaxBuilder public import SwiftSyntaxMacros -#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY -#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand @Suite") -#endif - /// A type describing the expansion of the `@Suite` attribute macro. /// /// This type is used to implement the `@Suite` attribute macro. Do not use it @@ -149,7 +145,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { result.append( """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") - private nonisolated static let \(accessorName): Testing.__TestContentRecordAccessor = { outValue, type, _, _ in + @c private nonisolated static func \(accessorName)(_ outValue: UnsafeMutableRawPointer, _ type: UnsafeRawPointer, _ hint: UnsafeRawPointer?, _: UInt) -> CBool { Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) } """ @@ -166,7 +162,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable { ) ) -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(<6.3) // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName("__🟡$") result.append( diff --git a/Sources/TestingMacros/Support/TestContentGeneration.swift b/Sources/TestingMacros/Support/TestContentGeneration.swift index 05214d1b8..314802005 100644 --- a/Sources/TestingMacros/Support/TestContentGeneration.swift +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift @@ -74,20 +74,18 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax? ) """ -#if hasFeature(SymbolLinkageMarkers) +#if compiler(>=6.3) result = """ - #if hasFeature(SymbolLinkageMarkers) #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS) - @_section("__DATA_CONST,__swift5_tests") + @section("__DATA_CONST,__swift5_tests") #elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI) - @_section("swift5_tests") + @section("swift5_tests") #elseif os(Windows) - @_section(".sw5test$B") + @section(".sw5test$B") #else @Testing.__testing(warning: "Platform-specific implementation missing: test content section name unavailable") #endif - @_used - #endif + @used \(result) """ #endif diff --git a/Sources/TestingMacros/TestDeclarationMacro.swift b/Sources/TestingMacros/TestDeclarationMacro.swift index 8007c3aaf..435f74b02 100644 --- a/Sources/TestingMacros/TestDeclarationMacro.swift +++ b/Sources/TestingMacros/TestDeclarationMacro.swift @@ -13,10 +13,6 @@ public import SwiftSyntax import SwiftSyntaxBuilder public import SwiftSyntaxMacros -#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY -#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand @Test") -#endif - /// A type describing the expansion of the `@Test` attribute macro. /// /// This type is used to implement the `@Test` attribute macro. Do not use it @@ -476,7 +472,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { result.append( """ @available(*, deprecated, message: "This property is an implementation detail of the testing library. Do not use it directly.") - private \(staticKeyword(for: typeName)) nonisolated let \(accessorName): Testing.__TestContentRecordAccessor = { outValue, type, _, _ in + @c private nonisolated \(staticKeyword(for: typeName)) func \(accessorName)(_ outValue: UnsafeMutableRawPointer, _ type: UnsafeRawPointer, _: UnsafeRawPointer?, _: UInt) -> CBool { Testing.Test.__store(\(generatorName), into: outValue, asTypeAt: type) } """ @@ -493,7 +489,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable { ) ) -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(<6.3) // Emit a type that contains a reference to the test content record. let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$") result.append( diff --git a/Sources/_TestDiscovery/TestContentRecord.swift b/Sources/_TestDiscovery/TestContentRecord.swift index b830026e2..1f1bd9c15 100644 --- a/Sources/_TestDiscovery/TestContentRecord.swift +++ b/Sources/_TestDiscovery/TestContentRecord.swift @@ -244,7 +244,7 @@ extension DiscoverableAsTestContent { return SectionBounds.all(.testContent).lazy.flatMap { sb in sb.buffer.withMemoryRebound(to: _TestContentRecord.self) { records in (0 ..< records.count).lazy - .map { (records.baseAddress! + $0) as UnsafePointer<_TestContentRecord> } + .map { records.baseAddress! + $0 } .filter { $0.pointee.kind == kind } .map { TestContentRecord(imageAddress: sb.imageAddress, recordAddress: $0) } } diff --git a/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift b/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift index aec6d2c10..c78fac75d 100644 --- a/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift +++ b/Tests/TestingMacrosTests/TestDeclarationMacroTests.swift @@ -472,10 +472,11 @@ struct TestDeclarationMacroTests { func differentFunctionTypes(input: String, expectedTypeName: String?, otherCode: String?) throws { let (output, _) = try parse(input) -#if hasFeature(SymbolLinkageMarkers) - #expect(output.contains("@_section")) -#endif -#if !SWT_NO_LEGACY_TEST_DISCOVERY +#if compiler(>=6.3) + #expect(output.contains("@section")) + #expect(!output.contains("__TestContentRecordContainer")) +#else + #expect(!output.contains("@section")) #expect(output.contains("__TestContentRecordContainer")) #endif if let expectedTypeName { diff --git a/Tests/TestingTests/DiscoveryTests.swift b/Tests/TestingTests/DiscoveryTests.swift index 24d2eecfa..2c415e001 100644 --- a/Tests/TestingTests/DiscoveryTests.swift +++ b/Tests/TestingTests/DiscoveryTests.swift @@ -58,7 +58,7 @@ struct DiscoveryTests { } #endif -#if !SWT_NO_DYNAMIC_LINKING && hasFeature(SymbolLinkageMarkers) +#if compiler(>=6.3) && !SWT_NO_DYNAMIC_LINKING struct MyTestContent: DiscoverableAsTestContent { typealias TestContentAccessorHint = UInt32 @@ -81,15 +81,15 @@ struct DiscoveryTests { } #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS) - @_section("__DATA_CONST,__swift5_tests") + @section("__DATA_CONST,__swift5_tests") #elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI) - @_section("swift5_tests") + @section("swift5_tests") #elseif os(Windows) - @_section(".sw5test$B") + @section(".sw5test$B") #else @__testing(warning: "Platform-specific implementation missing: test content section name unavailable") #endif - @_used + @used private static let record: __TestContentRecord = ( 0xABCD1234, 0, @@ -143,21 +143,4 @@ struct DiscoveryTests { }) } #endif - -#if !SWT_NO_LEGACY_TEST_DISCOVERY && hasFeature(SymbolLinkageMarkers) - @Test("Legacy test discovery finds the same number of tests") func discoveredTestCount() async { - let oldFlag = Environment.variable(named: "SWT_USE_LEGACY_TEST_DISCOVERY") - defer { - Environment.setVariable(oldFlag, named: "SWT_USE_LEGACY_TEST_DISCOVERY") - } - - Environment.setVariable("1", named: "SWT_USE_LEGACY_TEST_DISCOVERY") - let testsWithOldCode = await Array(Test.all).count - - Environment.setVariable("0", named: "SWT_USE_LEGACY_TEST_DISCOVERY") - let testsWithNewCode = await Array(Test.all).count - - #expect(testsWithOldCode == testsWithNewCode) - } -#endif }