Skip to content

Commit 2643e8d

Browse files
committed
[stdlib] Add build option to enable _debugPrecondition in Release mode
It is sometimes desirable to always perform (relatively cheap) runtime checks in the stdlib, even in configurations where we’d otherwise elide them. Add a build-time option to the standard library (`SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE`) to make `_debugPrecondition` work like `_precondition`, i.e., to enable it even in ReleaseAssert configurations. This option will keep additional checks in the following places, even in release mode: - Range checking in the subscript operations of all unsafe buffer pointer types. - Nil checking in `Optional.unsafelyUnwrapped` - Additional argument validation in `Unsafe[Mutable][Raw]Pointer`’s initialization/assignment/move/deinitialization/binding methods - Protection against initializing `Unsafe[Mutable][Raw]Pointer` with invalid data. (Negative count, nil pointer for non-empty buffer, etc) - Checks against index overflow in `Unsafe[Mutable]BufferPointer`’s index manipulation methods - Checks against backward ranges in `Range(uncheckedBounds:)`, `ClosedRange(uncheckedBounds:)` - Dynamic isa check in `unsafeDowncast(_:to:)` - Additional [cheap] checks to catch invalid Sequence/Collection implementations in `Array.init<S:Sequence>(_:)` and elsewhere - Checks against `Character` containing multiple grapheme clusters - More index validation in `EmptyCollection` (Additional cases will get added as the stdlib evolves.) The option is disabled by default — so `_debugPrecondition`s continue to be disabled in optimized builds, even after this change lands, unless someone specifically builds a stdlib that enables them. rdar://89118585
1 parent 0011b07 commit 2643e8d

File tree

4 files changed

+26
-0
lines changed

4 files changed

+26
-0
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ option(SWIFT_ENABLE_STDLIBCORE_EXCLUSIVITY_CHECKING
434434
"Build stdlibCore with exclusivity checking enabled"
435435
FALSE)
436436

437+
option(SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE
438+
"Enable _debugPrecondition checks in the stdlib in Release configurations"
439+
FALSE)
440+
437441
option(SWIFT_ENABLE_EXPERIMENTAL_DIFFERENTIABLE_PROGRAMMING
438442
"Enable experimental Swift differentiable programming features"
439443
FALSE)

stdlib/public/core/Assert.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,24 +261,32 @@ internal func _debugPrecondition(
261261
_ condition: @autoclosure () -> Bool, _ message: StaticString = StaticString(),
262262
file: StaticString = #file, line: UInt = #line
263263
) {
264+
#if SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE
265+
_precondition(condition(), message, file: file, line: line)
266+
#else
264267
// Only check in debug mode.
265268
if _slowPath(_isDebugAssertConfiguration()) {
266269
if !_fastPath(condition()) {
267270
_fatalErrorMessage("Fatal error", message, file: file, line: line,
268271
flags: _fatalErrorFlags())
269272
}
270273
}
274+
#endif
271275
}
272276

273277
@usableFromInline @_transparent
274278
internal func _debugPreconditionFailure(
275279
_ message: StaticString = StaticString(),
276280
file: StaticString = #file, line: UInt = #line
277281
) -> Never {
282+
#if SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE
283+
_preconditionFailure(message, file: file, line: line)
284+
#else
278285
if _slowPath(_isDebugAssertConfiguration()) {
279286
_precondition(false, message, file: file, line: line)
280287
}
281288
_conditionallyUnreachable()
289+
#endif
282290
}
283291

284292
/// Internal checks.

stdlib/public/core/AssertCommon.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ func _isStdlibInternalChecksEnabled() -> Bool {
5858
#endif
5959
}
6060

61+
@_transparent
62+
@_alwaysEmitIntoClient // Introduced in 5.7
63+
public // @testable
64+
func _isStdlibDebugChecksEnabled() -> Bool {
65+
#if SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE
66+
return !_isFastAssertConfiguration()
67+
#else
68+
return _isDebugAssertConfiguration()
69+
#endif
70+
}
71+
6172
@usableFromInline @_transparent
6273
internal func _fatalErrorFlags() -> UInt32 {
6374
// The current flags are:

stdlib/public/core/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ endif()
272272
if(SWIFT_STDLIB_ENABLE_STDLIBCORE_EXCLUSIVITY_CHECKING)
273273
list(APPEND swift_stdlib_compile_flags "-enforce-exclusivity=checked")
274274
endif()
275+
if(SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE)
276+
list(APPEND swift_stdlib_compile_flags "-DSWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE")
277+
endif()
275278
set(compile_flags_for_final_build)
276279
if(SWIFT_ENABLE_ARRAY_COW_CHECKS)
277280
list(APPEND compile_flags_for_final_build "-DCOW_CHECKS_ENABLED")

0 commit comments

Comments
 (0)