Skip to content

Commit a51a5de

Browse files
committed
Build settings for warning treating rules (SE-0443, draft)
1 parent 3f5c58c commit a51a5de

13 files changed

+1146
-10
lines changed

Diff for: Sources/Build/BuildDescription/ClangModuleBuildDescription.swift

+11-4
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,18 @@ public final class ClangModuleBuildDescription {
363363

364364
// suppress warnings if the package is remote
365365
if self.package.isRemote {
366-
args += ["-w"]
367-
// `-w` (suppress warnings) and `-Werror` (warnings as errors) flags are mutually exclusive
368-
if let index = args.firstIndex(of: "-Werror") {
369-
args.remove(at: index)
366+
// `-w` (suppress warnings) and the other warning control flags are mutually exclusive
367+
args = args.filter { arg in
368+
// we consider the following flags:
369+
// -Wxxxx
370+
// -Wno-xxxx
371+
// -Werror
372+
// -Werror=xxxx
373+
// -Wno-error
374+
// -Wno-error=xxxx
375+
arg.count <= 2 || !arg.starts(with: "-W")
370376
}
377+
args += ["-w"]
371378
}
372379

373380
return args

Diff for: Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift

+20-4
Original file line numberDiff line numberDiff line change
@@ -621,11 +621,27 @@ public final class SwiftModuleBuildDescription {
621621

622622
// suppress warnings if the package is remote
623623
if self.package.isRemote {
624-
args += ["-suppress-warnings"]
625-
// suppress-warnings and warnings-as-errors are mutually exclusive
626-
if let index = args.firstIndex(of: "-warnings-as-errors") {
627-
args.remove(at: index)
624+
// suppress-warnings and the other warning control flags are mutually exclusive
625+
var removeNextArg = false
626+
args = args.filter { arg in
627+
if removeNextArg {
628+
removeNextArg = false
629+
return false
630+
}
631+
switch arg {
632+
case "-warnings-as-errors", "-no-warnings-as-errors":
633+
return false
634+
case "-Wwarning", "-Werror":
635+
removeNextArg = true
636+
return false
637+
default:
638+
return true
639+
}
628640
}
641+
guard !removeNextArg else {
642+
throw InternalError("Unexpected '-Wwarning' or '-Werror' at the end of args")
643+
}
644+
args += ["-suppress-warnings"]
629645
}
630646

631647
// Pass `-user-module-version` for versioned packages that aren't pre-releases.

Diff for: Sources/PackageDescription/BuildSettings.swift

+220
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,92 @@ public struct CSetting: Sendable {
201201
public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CSetting {
202202
return CSetting(name: "unsafeFlags", value: flags, condition: condition)
203203
}
204+
205+
/// Controls how all C compiler warnings are treated during compilation.
206+
///
207+
/// Use this setting to specify whether all warnings should be treated as warnings (default behavior)
208+
/// or as errors. This is equivalent to passing `-Werror` or `-Wno-error`
209+
/// to the C compiler.
210+
///
211+
/// This setting applies to all warnings emitted by the C compiler. To control specific
212+
/// warnings individually, use `treatWarning(name:as:_:)` instead.
213+
///
214+
/// - Since: First available in PackageDescription 6.2.
215+
///
216+
/// - Parameters:
217+
/// - level: The treatment level for all warnings (`.warning` or `.error`).
218+
/// - condition: A condition that restricts the application of the build setting.
219+
@available(_PackageDescription, introduced: 6.2)
220+
public static func treatAllWarnings(
221+
as level: WarningLevel,
222+
_ condition: BuildSettingCondition? = nil
223+
) -> CSetting {
224+
return CSetting(
225+
name: "treatAllWarnings", value: [level.rawValue], condition: condition)
226+
}
227+
228+
/// Controls how a specific C compiler warning is treated during compilation.
229+
///
230+
/// Use this setting to specify whether a particular warning should be treated as a warning
231+
/// (default behavior) or as an error. This is equivalent to passing `-Werror=` or `-Wno-error=`
232+
/// followed by the warning name to the C compiler.
233+
///
234+
/// This setting allows for fine-grained control over individual warnings. To control all
235+
/// warnings at once, use `treatAllWarnings(as:_:)` instead.
236+
///
237+
/// - Since: First available in PackageDescription 6.2.
238+
///
239+
/// - Parameters:
240+
/// - name: The name of the specific warning to control.
241+
/// - level: The treatment level for the warning (`.warning` or `.error`).
242+
/// - condition: A condition that restricts the application of the build setting.
243+
@available(_PackageDescription, introduced: 6.2)
244+
public static func treatWarning(
245+
_ name: String,
246+
as level: WarningLevel,
247+
_ condition: BuildSettingCondition? = nil
248+
) -> CSetting {
249+
return CSetting(
250+
name: "treatWarning", value: [name, level.rawValue], condition: condition)
251+
}
252+
253+
/// Enable a specific C compiler warning group.
254+
///
255+
/// Use this setting to enable a specific warning group. This is equivalent to passing
256+
/// `-W` followed by the group name to the C compiler.
257+
///
258+
/// - Since: First available in PackageDescription 6.2.
259+
///
260+
/// - Parameters:
261+
/// - name: The name of the warning group to enable.
262+
/// - condition: A condition that restricts the application of the build setting.
263+
@available(_PackageDescription, introduced: 6.2)
264+
public static func enableWarning(
265+
_ name: String,
266+
_ condition: BuildSettingCondition? = nil
267+
) -> CSetting {
268+
return CSetting(
269+
name: "enableWarning", value: [name], condition: condition)
270+
}
271+
272+
/// Disable a specific C compiler warning group.
273+
///
274+
/// Use this setting to disable a specific warning group. This is equivalent to passing
275+
/// `-Wno-` followed by the group name to the C compiler.
276+
///
277+
/// - Since: First available in PackageDescription 6.2.
278+
///
279+
/// - Parameters:
280+
/// - name: The name of the warning group to disable.
281+
/// - condition: A condition that restricts the application of the build setting.
282+
@available(_PackageDescription, introduced: 6.2)
283+
public static func disableWarning(
284+
_ name: String,
285+
_ condition: BuildSettingCondition? = nil
286+
) -> CSetting {
287+
return CSetting(
288+
name: "disableWarning", value: [name], condition: condition)
289+
}
204290
}
205291

206292
/// A CXX-language build setting.
@@ -271,6 +357,92 @@ public struct CXXSetting: Sendable {
271357
public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CXXSetting {
272358
return CXXSetting(name: "unsafeFlags", value: flags, condition: condition)
273359
}
360+
361+
/// Controls how all C++ compiler warnings are treated during compilation.
362+
///
363+
/// Use this setting to specify whether all warnings should be treated as warnings (default behavior)
364+
/// or as errors. This is equivalent to passing `-Werror` or `-Wno-error`
365+
/// to the C++ compiler.
366+
///
367+
/// This setting applies to all warnings emitted by the C++ compiler. To control specific
368+
/// warnings individually, use `treatWarning(name:as:_:)` instead.
369+
///
370+
/// - Since: First available in PackageDescription 6.2.
371+
///
372+
/// - Parameters:
373+
/// - level: The treatment level for all warnings (`.warning` or `.error`).
374+
/// - condition: A condition that restricts the application of the build setting.
375+
@available(_PackageDescription, introduced: 6.2)
376+
public static func treatAllWarnings(
377+
as level: WarningLevel,
378+
_ condition: BuildSettingCondition? = nil
379+
) -> CXXSetting {
380+
return CXXSetting(
381+
name: "treatAllWarnings", value: [level.rawValue], condition: condition)
382+
}
383+
384+
/// Controls how a specific C++ compiler warning is treated during compilation.
385+
///
386+
/// Use this setting to specify whether a particular warning should be treated as a warning
387+
/// (default behavior) or as an error. This is equivalent to passing `-Werror=` or `-Wno-error=`
388+
/// followed by the warning name to the C++ compiler.
389+
///
390+
/// This setting allows for fine-grained control over individual warnings. To control all
391+
/// warnings at once, use `treatAllWarnings(as:_:)` instead.
392+
///
393+
/// - Since: First available in PackageDescription 6.2.
394+
///
395+
/// - Parameters:
396+
/// - name: The name of the specific warning to control.
397+
/// - level: The treatment level for the warning (`.warning` or `.error`).
398+
/// - condition: A condition that restricts the application of the build setting.
399+
@available(_PackageDescription, introduced: 6.2)
400+
public static func treatWarning(
401+
_ name: String,
402+
as level: WarningLevel,
403+
_ condition: BuildSettingCondition? = nil
404+
) -> CXXSetting {
405+
return CXXSetting(
406+
name: "treatWarning", value: [name, level.rawValue], condition: condition)
407+
}
408+
409+
/// Enable a specific C++ compiler warning group.
410+
///
411+
/// Use this setting to enable a specific warning group. This is equivalent to passing
412+
/// `-W` followed by the group name to the C++ compiler.
413+
///
414+
/// - Since: First available in PackageDescription 6.2.
415+
///
416+
/// - Parameters:
417+
/// - name: The name of the warning group to enable.
418+
/// - condition: A condition that restricts the application of the build setting.
419+
@available(_PackageDescription, introduced: 6.2)
420+
public static func enableWarning(
421+
_ name: String,
422+
_ condition: BuildSettingCondition? = nil
423+
) -> CXXSetting {
424+
return CXXSetting(
425+
name: "enableWarning", value: [name], condition: condition)
426+
}
427+
428+
/// Disable a specific C++ compiler warning group.
429+
///
430+
/// Use this setting to disable a specific warning group. This is equivalent to passing
431+
/// `-Wno-` followed by the group name to the C++ compiler.
432+
///
433+
/// - Since: First available in PackageDescription 6.2.
434+
///
435+
/// - Parameters:
436+
/// - name: The name of the warning group to disable.
437+
/// - condition: A condition that restricts the application of the build setting.
438+
@available(_PackageDescription, introduced: 6.2)
439+
public static func disableWarning(
440+
_ name: String,
441+
_ condition: BuildSettingCondition? = nil
442+
) -> CXXSetting {
443+
return CXXSetting(
444+
name: "disableWarning", value: [name], condition: condition)
445+
}
274446
}
275447

276448
/// A Swift language build setting.
@@ -463,6 +635,54 @@ public struct SwiftSetting: Sendable {
463635
name: "swiftLanguageMode", value: [.init(describing: mode)], condition: condition)
464636
}
465637

638+
/// Controls how all Swift compiler warnings are treated during compilation.
639+
///
640+
/// Use this setting to specify whether all warnings should be treated as warnings (default behavior)
641+
/// or as errors. This is equivalent to passing `-warnings-as-errors` or `-no-warnings-as-errors`
642+
/// to the Swift compiler.
643+
///
644+
/// This setting applies to all warnings emitted by the Swift compiler. To control specific
645+
/// warnings individually, use `treatWarning(name:as:_:)` instead.
646+
///
647+
/// - Since: First available in PackageDescription 6.2.
648+
///
649+
/// - Parameters:
650+
/// - level: The treatment level for all warnings (`.warning` or `.error`).
651+
/// - condition: A condition that restricts the application of the build setting.
652+
@available(_PackageDescription, introduced: 6.2)
653+
public static func treatAllWarnings(
654+
as level: WarningLevel,
655+
_ condition: BuildSettingCondition? = nil
656+
) -> SwiftSetting {
657+
return SwiftSetting(
658+
name: "treatAllWarnings", value: [level.rawValue], condition: condition)
659+
}
660+
661+
/// Controls how a specific Swift compiler warning is treated during compilation.
662+
///
663+
/// Use this setting to specify whether a particular warning should be treated as a warning
664+
/// (default behavior) or as an error. This is equivalent to passing `-Werror` or `-Wwarning`
665+
/// followed by the warning name to the Swift compiler.
666+
///
667+
/// This setting allows for fine-grained control over individual warnings. To control all
668+
/// warnings at once, use `treatAllWarnings(as:_:)` instead.
669+
///
670+
/// - Since: First available in PackageDescription 6.2.
671+
///
672+
/// - Parameters:
673+
/// - name: The name of the specific warning to control.
674+
/// - level: The treatment level for the warning (`.warning` or `.error`).
675+
/// - condition: A condition that restricts the application of the build setting.
676+
@available(_PackageDescription, introduced: 6.2)
677+
public static func treatWarning(
678+
_ name: String,
679+
as level: WarningLevel,
680+
_ condition: BuildSettingCondition? = nil
681+
) -> SwiftSetting {
682+
return SwiftSetting(
683+
name: "treatWarning", value: [name, level.rawValue], condition: condition)
684+
}
685+
466686
/// Set the default isolation to the given global actor type.
467687
///
468688
/// - Since: First available in PackageDescription 6.2.

Diff for: Sources/PackageDescription/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ add_library(PackageDescription
2323
Target.swift
2424
Trait.swift
2525
Version.swift
26-
Version+StringLiteralConvertible.swift)
26+
Version+StringLiteralConvertible.swift
27+
WarningLevel.swift)
2728

2829
target_compile_options(PackageDescription PUBLIC
2930
$<$<COMPILE_LANGUAGE:Swift>:-package-description-version$<SEMICOLON>999.0>)

Diff for: Sources/PackageDescription/WarningLevel.swift

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// This source file is part of the Swift open source project
3+
//
4+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
5+
// Licensed under Apache License v2.0 with Runtime Library Exception
6+
//
7+
// See http://swift.org/LICENSE.txt for license information
8+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
/// The level at which a compiler warning should be treated.
13+
///
14+
/// This enum is used with the `SwiftSetting.treatAllWarnings(as:_:)` and
15+
/// `SwiftSetting.treatWarning(name:as:_:)` methods to control how warnings
16+
/// are handled during compilation.
17+
@available(_PackageDescription, introduced: 6.2)
18+
public enum WarningLevel: String {
19+
/// Treat as a warning.
20+
///
21+
/// Warnings will be displayed during compilation but will not cause the build to fail.
22+
case warning
23+
24+
/// Treat as an error.
25+
///
26+
/// Warnings will be elevated to errors, causing the build to fail if any such warnings occur.
27+
case error
28+
}

Diff for: Sources/PackageLoading/ManifestJSONParser.swift

+39
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,45 @@ extension TargetBuildSettingDescription.Kind {
749749
}
750750

751751
return .swiftLanguageMode(version)
752+
case "treatAllWarnings":
753+
guard values.count == 1 else {
754+
throw InternalError("invalid build settings value")
755+
}
756+
757+
let rawLevel = values[0]
758+
759+
guard let level = TargetBuildSettingDescription.WarningLevel(rawValue: rawLevel) else {
760+
throw InternalError("unknown warning treat level: \(rawLevel)")
761+
}
762+
763+
return .treatAllWarnings(level)
764+
765+
case "treatWarning":
766+
guard values.count == 2 else {
767+
throw InternalError("invalid build settings value")
768+
}
769+
770+
let name = values[0]
771+
let rawValue = values[1]
772+
773+
guard let level = TargetBuildSettingDescription.WarningLevel(rawValue: rawValue) else {
774+
throw InternalError("unknown warning treat level: \(rawValue)")
775+
}
776+
777+
return .treatWarning(name, level)
778+
779+
case "enableWarning":
780+
guard values.count == 1 else {
781+
throw InternalError("invalid build settings value")
782+
}
783+
return .enableWarning(values[0])
784+
785+
case "disableWarning":
786+
guard values.count == 1 else {
787+
throw InternalError("invalid build settings value")
788+
}
789+
return .disableWarning(values[0])
790+
752791
case "defaultIsolation":
753792
guard let rawValue = values.first else {
754793
throw InternalError("invalid (empty) build settings value")

0 commit comments

Comments
 (0)