Skip to content

Commit 3670d67

Browse files
authored
Adopt @section and @used. (#1408)
This PR adopts the `@section` and `@used` attributes now available in the Swift 6.3 toolchain. These attributes replace the experimental `@_section` and `@_used` attributes verbatim and they are always enabled (so no need to check `hasFeature(SymbolLinkageMarkers)`.) Because these attributes are only available with the Swift 6.3 toolchain, we do not use them when building with Swift 6.2. Instead, if you build with Swift 6.2 you continue to use the "legacy" test discovery mechanism based on type metadata emission. The "legacy" mechanism will be removed in a future update. Because the `_TestDiscovery` target needs to continue to compile with Swift 6.2, I have not switched us over to `objectFormat()` yet. See #1370 for details. Resolves #1371. Resolves rdar://136789701. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 526bd77 commit 3670d67

10 files changed

Lines changed: 44 additions & 57 deletions

File tree

Documentation/Porting.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ to load that information:
193193
```
194194

195195
You will also need to update the `makeTestContentRecordDecl()` function in the
196-
`TestingMacros` target to emit the correct `@_section` attribute for your
196+
`TestingMacros` target to emit the correct `@section` attribute for your
197197
platform. If your platform uses the ELF image format and supports the
198198
`dl_iterate_phdr()` function, add it to the existing `#elseif os(Linux) || ...`
199199
case. Otherwise, add a new case for your platform:
@@ -203,7 +203,7 @@ case. Otherwise, add a new case for your platform:
203203
+++ b/Sources/TestingMacros/Support/TestContentGeneration.swift
204204
// ...
205205
+ #elseif os(Classic)
206-
+ @_section(".rsrc,swft,__swift5_tests")
206+
+ @section(".rsrc,swft,__swift5_tests")
207207
#else
208208
@__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
209209
#endif
@@ -214,6 +214,11 @@ directly into test authors' test targets, so you will not be able to use
214214
compiler conditionals defined in the Swift Testing package (including those that
215215
start with `"SWT_"`).
216216

217+
> [!NOTE]
218+
> We are not using `objectFormat()` yet to maintain compatibility with the Swift
219+
> 6.2 toolchain. We will migrate to `objectFormat()` when we drop Swift 6.2
220+
> toolchain support (presumably after Swift 6.3 ships).
221+
217222
## Runtime test discovery with static linkage
218223

219224
If your platform does not support dynamic linking and loading, you will need to

Package.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,11 +379,6 @@ extension Array where Element == PackageDescription.SwiftSetting {
379379

380380
.enableUpcomingFeature("MemberImportVisibility"),
381381

382-
// This setting is enabled in the package, but not in the toolchain build
383-
// (via CMake). Enabling it is dependent on acceptance of the @section
384-
// proposal via Swift Evolution.
385-
.enableExperimentalFeature("SymbolLinkageMarkers"),
386-
387382
// Enabled to allow tests to be added to ~Escapable suites.
388383
.enableExperimentalFeature("Lifetimes"),
389384

Sources/Testing/Discovery+Macro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public typealias __TestContentRecordAccessor = @convention(c) (
3434
public typealias __TestContentRecord = (
3535
kind: UInt32,
3636
reserved1: UInt32,
37-
accessor: __TestContentRecordAccessor?,
37+
accessor: __TestContentRecordAccessor,
3838
context: UInt,
3939
reserved2: UInt
4040
)

Sources/TestingMacros/ConditionMacro.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ public import SwiftSyntax
1313
import SwiftSyntaxBuilder
1414
public import SwiftSyntaxMacros
1515

16-
#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY
17-
#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand #expect(processExitsWith:)")
18-
#endif
19-
2016
/// A protocol containing the common implementation for the expansions of the
2117
/// `#expect()` and `#require()` macros.
2218
///
@@ -496,7 +492,7 @@ extension ExitTestConditionMacro {
496492

497493
// Create another local type for legacy test discovery.
498494
var recordDecl: DeclSyntax?
499-
#if !SWT_NO_LEGACY_TEST_DISCOVERY
495+
#if compiler(<6.3)
500496
let legacyEnumName = context.makeUniqueName("__🟡$")
501497
recordDecl = """
502498
enum \(legacyEnumName): Testing.__TestContentRecordContainer {

Sources/TestingMacros/SuiteDeclarationMacro.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ public import SwiftSyntax
1313
import SwiftSyntaxBuilder
1414
public import SwiftSyntaxMacros
1515

16-
#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY
17-
#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand @Suite")
18-
#endif
19-
2016
/// A type describing the expansion of the `@Suite` attribute macro.
2117
///
2218
/// This type is used to implement the `@Suite` attribute macro. Do not use it
@@ -166,7 +162,7 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable {
166162
)
167163
)
168164

169-
#if !SWT_NO_LEGACY_TEST_DISCOVERY
165+
#if compiler(<6.3)
170166
// Emit a type that contains a reference to the test content record.
171167
let enumName = context.makeUniqueName("__🟡$")
172168
result.append(

Sources/TestingMacros/Support/TestContentGeneration.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,26 +68,24 @@ func makeTestContentRecordDecl(named name: TokenSyntax, in typeName: TypeSyntax?
6868
private nonisolated \(staticKeyword(for: typeName)) let \(name): Testing.__TestContentRecord = (
6969
\(kindExpr), \(kind.commentRepresentation)
7070
0,
71-
unsafe \(accessorName),
71+
{ unsafe \(accessorName)($0, $1, $2, $3) },
7272
\(contextExpr),
7373
0
7474
)
7575
"""
7676

77-
#if hasFeature(SymbolLinkageMarkers)
77+
#if compiler(>=6.3)
7878
result = """
79-
#if hasFeature(SymbolLinkageMarkers)
8079
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
81-
@_section("__DATA_CONST,__swift5_tests")
80+
@section("__DATA_CONST,__swift5_tests")
8281
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
83-
@_section("swift5_tests")
82+
@section("swift5_tests")
8483
#elseif os(Windows)
85-
@_section(".sw5test$B")
84+
@section(".sw5test$B")
8685
#else
8786
@Testing.__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
8887
#endif
89-
@_used
90-
#endif
88+
@used
9189
\(result)
9290
"""
9391
#endif

Sources/TestingMacros/TestDeclarationMacro.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ public import SwiftSyntax
1313
import SwiftSyntaxBuilder
1414
public import SwiftSyntaxMacros
1515

16-
#if !hasFeature(SymbolLinkageMarkers) && SWT_NO_LEGACY_TEST_DISCOVERY
17-
#error("Platform-specific misconfiguration: either SymbolLinkageMarkers or legacy test discovery is required to expand @Test")
18-
#endif
19-
2016
/// A type describing the expansion of the `@Test` attribute macro.
2117
///
2218
/// This type is used to implement the `@Test` attribute macro. Do not use it
@@ -491,7 +487,7 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
491487
)
492488
)
493489

494-
#if !SWT_NO_LEGACY_TEST_DISCOVERY
490+
#if compiler(<6.3)
495491
// Emit a type that contains a reference to the test content record.
496492
let enumName = context.makeUniqueName(thunking: functionDecl, withPrefix: "__🟡$")
497493
result.append(

Sources/_TestDiscovery/TestContentRecord.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ extension DiscoverableAsTestContent {
244244
return SectionBounds.all(.testContent).lazy.flatMap { sb in
245245
sb.buffer.withMemoryRebound(to: _TestContentRecord.self) { records in
246246
(0 ..< records.count).lazy
247-
.map { (records.baseAddress! + $0) as UnsafePointer<_TestContentRecord> }
247+
.map { records.baseAddress! + $0 }
248248
.filter { $0.pointee.kind == kind }
249249
.map { TestContentRecord<Self>(imageAddress: sb.imageAddress, recordAddress: $0) }
250250
}

Tests/TestingMacrosTests/TestDeclarationMacroTests.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -486,10 +486,11 @@ struct TestDeclarationMacroTests {
486486
func differentFunctionTypes(input: String, expectedTypeName: String?, otherCode: String?) throws {
487487
let (output, _) = try parse(input)
488488

489-
#if hasFeature(SymbolLinkageMarkers)
490-
#expect(output.contains("@_section"))
491-
#endif
492-
#if !SWT_NO_LEGACY_TEST_DISCOVERY
489+
#if compiler(>=6.3)
490+
#expect(output.contains("@section"))
491+
#expect(!output.contains("__TestContentRecordContainer"))
492+
#else
493+
#expect(!output.contains("@section"))
493494
#expect(output.contains("__TestContentRecordContainer"))
494495
#endif
495496
if let expectedTypeName {

Tests/TestingTests/DiscoveryTests.swift

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct DiscoveryTests {
5858
}
5959
#endif
6060

61-
#if !SWT_NO_DYNAMIC_LINKING && hasFeature(SymbolLinkageMarkers)
61+
#if compiler(>=6.3) && !SWT_NO_DYNAMIC_LINKING
6262
struct MyTestContent: DiscoverableAsTestContent {
6363
typealias TestContentAccessorHint = UInt32
6464

@@ -81,16 +81,16 @@ struct DiscoveryTests {
8181
}
8282

8383
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
84-
@_section("__DATA_CONST,__swift5_tests")
84+
@section("__DATA_CONST,__swift5_tests")
8585
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || os(WASI)
86-
@_section("swift5_tests")
86+
@section("swift5_tests")
8787
#elseif os(Windows)
88-
@_section(".sw5test$B")
88+
@section(".sw5test$B")
8989
#else
9090
@__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
9191
#endif
92-
@_used
93-
private static let record: __TestContentRecord = (
92+
@used
93+
fileprivate static let record: __TestContentRecord = (
9494
0xABCD1234,
9595
0,
9696
{ outValue, type, hint, _ in
@@ -105,12 +105,12 @@ struct DiscoveryTests {
105105
_ = outValue.initializeMemory(as: Self.self, to: .init(value: expectedValue))
106106
return true
107107
},
108-
UInt(truncatingIfNeeded: UInt64(0x0204060801030507)),
108+
0x02040608,
109109
0
110110
)
111111
}
112112

113-
@Test func testDiscovery() async {
113+
@Test func testDiscovery() {
114114
// Check the type of the test record sequence (it should be lazy.)
115115
let allRecordsSeq = MyTestContent.allTestContentRecords()
116116
#if SWT_FIXED_143080508
@@ -142,22 +142,22 @@ struct DiscoveryTests {
142142
&& record.context == MyTestContent.expectedContext
143143
})
144144
}
145-
#endif
146145

147-
#if !SWT_NO_LEGACY_TEST_DISCOVERY && hasFeature(SymbolLinkageMarkers)
148-
@Test("Legacy test discovery finds the same number of tests") func discoveredTestCount() async {
149-
let oldFlag = Environment.variable(named: "SWT_USE_LEGACY_TEST_DISCOVERY")
150-
defer {
151-
Environment.setVariable(oldFlag, named: "SWT_USE_LEGACY_TEST_DISCOVERY")
146+
#if !SWT_NO_LEGACY_TEST_DISCOVERY
147+
struct `__🟡$LegacyTestContentRecord`: __TestContentRecordContainer {
148+
static var __testContentRecord: __TestContentRecord {
149+
MyTestContent.record
152150
}
151+
}
153152

154-
Environment.setVariable("1", named: "SWT_USE_LEGACY_TEST_DISCOVERY")
155-
let testsWithOldCode = await Array(Test.all).count
156-
157-
Environment.setVariable("0", named: "SWT_USE_LEGACY_TEST_DISCOVERY")
158-
let testsWithNewCode = await Array(Test.all).count
159-
160-
#expect(testsWithOldCode == testsWithNewCode)
153+
@Test func legacyTestDiscovery() throws {
154+
let allRecords = Array(MyTestContent.allTypeMetadataBasedTestContentRecords())
155+
#expect(allRecords.count == 1)
156+
let record = try #require(allRecords.first)
157+
#expect(record.context == MyTestContent.expectedContext)
158+
let content = try #require(record.load())
159+
#expect(content.value == MyTestContent.expectedValue)
161160
}
162161
#endif
162+
#endif
163163
}

0 commit comments

Comments
 (0)