Skip to content

Commit ad0cd52

Browse files
authored
[SE-0458] Implement the strictMemorySafety Swift setting (#8314)
Implements the `strictMemorySafety` Swift setting introduced in [SE-0458](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md).
1 parent 150b709 commit ad0cd52

File tree

10 files changed

+88
-3
lines changed

10 files changed

+88
-3
lines changed

CHANGELOG.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ Note: This is in reverse chronological order, so newer entries are added to the
33
Swift Next
44
-----------
55

6+
Swift 6.2
7+
---------
8+
9+
* [#8314]
10+
11+
Starting from tools-version 6.2, `SwiftSetting` provides a `strictMemorySafety` setting to enable the strict memory safety checking introduced in [SE-0458].
12+
613
Swift 6.0
714
-----------
815

@@ -393,7 +400,7 @@ Swift 3.0
393400
[SE-0387]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0387-cross-compilation-destinations.md
394401
[SE-0391]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0391-package-registry-publish.md
395402
[SE-0387 proposal text]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0387-cross-compilation-destinations.md#swift-sdk-installation-and-configuration
396-
403+
[SE-0458]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md
397404
[SR-5918]: https://bugs.swift.org/browse/SR-5918
398405
[SR-6978]: https://bugs.swift.org/browse/SR-6978
399406
[SR-13566]: https://bugs.swift.org/browse/SR-13566

Sources/Build/BuildDescription/ProductBuildDescription.swift

+11-1
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,26 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
283283
// Pass experimental features to link jobs in addition to compile jobs. Preserve ordering while eliminating
284284
// duplicates with `OrderedSet`.
285285
var experimentalFeatures = OrderedSet<String>()
286+
var strictMemorySafety = false
286287
for target in self.product.modules {
287288
let swiftSettings = target.underlying.buildSettingsDescription.filter { $0.tool == .swift }
288-
for case let .enableExperimentalFeature(feature) in swiftSettings.map(\.kind) {
289+
for kind in swiftSettings.map(\.kind) {
290+
if case let .enableExperimentalFeature(feature) = kind {
289291
experimentalFeatures.append(feature)
292+
} else if kind == .strictMemorySafety {
293+
strictMemorySafety = true
290294
}
295+
}
291296
}
297+
292298
for feature in experimentalFeatures {
293299
args += ["-enable-experimental-feature", feature]
294300
}
295301

302+
if strictMemorySafety {
303+
args.append("-strict-memory-safety")
304+
}
305+
296306
// Embed the swift stdlib library path inside tests and executables on Darwin.
297307
let useStdlibRpath: Bool
298308
switch self.product.type {

Sources/PackageDescription/BuildSettings.swift

+22
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,28 @@ public struct SwiftSetting: Sendable {
379379
name: "enableExperimentalFeature", value: [name], condition: condition)
380380
}
381381

382+
/// Enable strict memory safety checking.
383+
///
384+
/// Strict memory safety checking is an opt-in compiler feature that
385+
/// identifies any uses of language constructs or APIs that break
386+
/// memory safety. Issues are reported as warnings and can generally
387+
/// be suppressed by adding annotations (such as `@unsafe` and `unsafe`)
388+
/// that acknowledge the presence of unsafe code, making it easier to
389+
/// review and audit at a later time.
390+
///
391+
/// - Since: First available in PackageDescription 6.2.
392+
///
393+
/// - Parameters:
394+
/// - condition: A condition that restricts the application of the build
395+
/// setting.
396+
@available(_PackageDescription, introduced: 6.2)
397+
public static func strictMemorySafety(
398+
_ condition: BuildSettingCondition? = nil
399+
) -> SwiftSetting {
400+
return SwiftSetting(
401+
name: "strictMemorySafety", value: ["ON"], condition: condition)
402+
}
403+
382404
public enum InteroperabilityMode: String {
383405
case C
384406
case Cxx

Sources/PackageLoading/ManifestJSONParser.swift

+2
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,8 @@ extension TargetBuildSettingDescription.Kind {
537537
throw InternalError("invalid (empty) build settings value")
538538
}
539539
return .enableExperimentalFeature(value)
540+
case "strictMemorySafety":
541+
return .strictMemorySafety
540542
case "unsafeFlags":
541543
return .unsafeFlags(values)
542544

Sources/PackageLoading/PackageBuilder.swift

+13
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,19 @@ public final class PackageBuilder {
12131213

12141214
values = ["-enable-experimental-feature", value]
12151215

1216+
case .strictMemorySafety:
1217+
switch setting.tool {
1218+
case .c, .cxx, .linker:
1219+
throw InternalError(
1220+
"only Swift supports strict memory safety"
1221+
)
1222+
1223+
case .swift:
1224+
decl = .OTHER_SWIFT_FLAGS
1225+
}
1226+
1227+
values = ["-strict-memory-safety"]
1228+
12161229
case .swiftLanguageMode(let version):
12171230
switch setting.tool {
12181231
case .c, .cxx, .linker:

Sources/PackageModel/Manifest/TargetBuildSettingDescription.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public enum TargetBuildSettingDescription {
3636

3737
case enableUpcomingFeature(String)
3838
case enableExperimentalFeature(String)
39+
case strictMemorySafety
3940

4041
case unsafeFlags([String])
4142

@@ -47,7 +48,7 @@ public enum TargetBuildSettingDescription {
4748
// If `.unsafeFlags` is used, but doesn't specify any flags, we treat it the same way as not specifying it.
4849
return !flags.isEmpty
4950
case .headerSearchPath, .define, .linkedLibrary, .linkedFramework, .interoperabilityMode,
50-
.enableUpcomingFeature, .enableExperimentalFeature, .swiftLanguageMode:
51+
.enableUpcomingFeature, .enableExperimentalFeature, .strictMemorySafety, .swiftLanguageMode:
5152
return false
5253
}
5354
}

Sources/PackageModel/ManifestSourceGeneration.swift

+4
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,8 @@ fileprivate extension SourceCodeFragment {
508508
params.append(SourceCodeFragment(from: condition))
509509
}
510510
self.init(enum: setting.kind.name, subnodes: params)
511+
case .strictMemorySafety:
512+
self.init(enum: setting.kind.name, subnodes: [])
511513
case .define(let value):
512514
let parts = value.split(separator: "=", maxSplits: 1)
513515
assert(parts.count == 1 || parts.count == 2)
@@ -686,6 +688,8 @@ extension TargetBuildSettingDescription.Kind {
686688
return "enableUpcomingFeature"
687689
case .enableExperimentalFeature:
688690
return "enableExperimentalFeature"
691+
case .strictMemorySafety:
692+
return "strictMemorySafety"
689693
case .swiftLanguageMode:
690694
return "swiftLanguageMode"
691695
}

Sources/PackageModel/ToolsVersion.swift

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public struct ToolsVersion: Equatable, Hashable, Codable, Sendable {
3333
public static let v5_10 = ToolsVersion(version: "5.10.0")
3434
public static let v6_0 = ToolsVersion(version: "6.0.0")
3535
public static let v6_1 = ToolsVersion(version: "6.1.0")
36+
public static let v6_2 = ToolsVersion(version: "6.2.0")
3637
public static let vNext = ToolsVersion(version: "999.0.0")
3738

3839
/// The current tools version in use.

Tests/BuildTests/BuildPlanTests.swift

+5
Original file line numberDiff line numberDiff line change
@@ -4247,6 +4247,7 @@ final class BuildPlanTests: XCTestCase {
42474247
kind: .enableUpcomingFeature("WorstFeature"),
42484248
condition: .init(platformNames: ["macos"], config: "debug")
42494249
),
4250+
.init(tool: .swift, kind: .strictMemorySafety),
42504251
]
42514252
),
42524253
TargetDescription(
@@ -4371,6 +4372,7 @@ final class BuildPlanTests: XCTestCase {
43714372
"-cxx-interoperability-mode=default",
43724373
"-Xcc", "-std=c++17",
43734374
"-enable-upcoming-feature", "BestFeature",
4375+
"-strict-memory-safety",
43744376
"-g",
43754377
"-Xcc", "-g",
43764378
"-Xcc", "-fno-omit-frame-pointer",
@@ -4435,6 +4437,7 @@ final class BuildPlanTests: XCTestCase {
44354437
"-Xcc", "-std=c++17",
44364438
"-enable-upcoming-feature",
44374439
"BestFeature",
4440+
"-strict-memory-safety",
44384441
"-g",
44394442
"-Xcc", "-g",
44404443
"-Xcc", "-fomit-frame-pointer",
@@ -4490,6 +4493,7 @@ final class BuildPlanTests: XCTestCase {
44904493
"-Xcc", "-std=c++17",
44914494
"-enable-upcoming-feature",
44924495
"BestFeature",
4496+
"-strict-memory-safety",
44934497
"-g",
44944498
"-Xcc", "-g",
44954499
"-Xcc", "-fno-omit-frame-pointer",
@@ -4534,6 +4538,7 @@ final class BuildPlanTests: XCTestCase {
45344538
"-Xcc", "-std=c++17",
45354539
"-enable-upcoming-feature", "BestFeature",
45364540
"-enable-upcoming-feature", "WorstFeature",
4541+
"-strict-memory-safety",
45374542
"-g",
45384543
"-Xcc", "-g",
45394544
.end,

Tests/WorkspaceTests/ManifestSourceGenerationTests.swift

+20
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,26 @@ final class ManifestSourceGenerationTests: XCTestCase {
615615
try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v5_8)
616616
}
617617

618+
func testStrictMemorySafety() async throws {
619+
let manifestContents = """
620+
// swift-tools-version:6.2
621+
import PackageDescription
622+
623+
let package = Package(
624+
name: "UpcomingAndExperimentalFeatures",
625+
targets: [
626+
.target(
627+
name: "MyTool",
628+
swiftSettings: [
629+
.strictMemorySafety(),
630+
]
631+
),
632+
]
633+
)
634+
"""
635+
try await testManifestWritingRoundTrip(manifestContents: manifestContents, toolsVersion: .v6_2)
636+
}
637+
618638
func testPluginNetworkingPermissionGeneration() async throws {
619639
let manifest = Manifest.createRootManifest(
620640
displayName: "thisPkg",

0 commit comments

Comments
 (0)