-
Notifications
You must be signed in to change notification settings - Fork 10.6k
stdlib: Print the error message in precondition() and preconditionFailure() even in release builds. #26215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stdlib: Print the error message in precondition() and preconditionFailure() even in release builds. #26215
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,10 +59,12 @@ public func assert( | |
/// | ||
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug | ||
/// configuration): If `condition` evaluates to `false`, stop program | ||
/// execution in a debuggable state after printing `message`. | ||
/// execution in a debuggable state after printing `message` | ||
/// along with the file and line information.. | ||
/// | ||
/// * In `-O` builds (the default for Xcode's Release configuration): If | ||
/// `condition` evaluates to `false`, stop program execution. | ||
/// `condition` evaluates to `false`, stop program execution state after | ||
/// printing `message`. | ||
/// | ||
/// * In `-Ounchecked` builds, `condition` is not evaluated, but the optimizer | ||
/// may assume that it *always* evaluates to `true`. Failure to satisfy that | ||
|
@@ -82,7 +84,7 @@ public func assert( | |
@_transparent | ||
public func precondition( | ||
_ condition: @autoclosure () -> Bool, | ||
_ message: @autoclosure () -> String = String(), | ||
_ message: @autoclosure () -> String, | ||
file: StaticString = #file, line: UInt = #line | ||
) { | ||
// Only check in debug and release mode. In release mode just trap. | ||
|
@@ -91,10 +93,55 @@ public func precondition( | |
_assertionFailure("Precondition failed", message(), file: file, line: line, | ||
flags: _fatalErrorFlags()) | ||
} | ||
} else if _isReleaseAssertConfiguration() { | ||
if !_fastPath(condition()) { | ||
_assertionFailure("Precondition failed", message(), | ||
flags: _fatalErrorFlags()) | ||
} | ||
} | ||
} | ||
|
||
/// Checks a necessary condition for making forward progress. | ||
/// | ||
/// Use this function to detect conditions that must prevent the program from | ||
/// proceeding, even in shipping code, but without a failure message. | ||
/// | ||
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug | ||
/// configuration): If `condition` evaluates to `false`, stop program | ||
/// execution in a debuggable state after printing "Precondition failed", | ||
/// along with the file and line information. | ||
/// | ||
/// * In `-O` builds (the default for Xcode's Release configuration): If | ||
/// `condition` evaluates to `false`, stop program execution. | ||
/// | ||
/// * In `-Ounchecked` builds, `condition` is not evaluated, but the optimizer | ||
/// may assume that it *always* evaluates to `true`. Failure to satisfy that | ||
/// assumption is a serious programming error. | ||
/// | ||
/// - Parameters: | ||
/// - condition: The condition to test. `condition` is not evaluated in | ||
/// `-Ounchecked` builds. | ||
/// - file: The file name to print with `message` if the precondition fails. | ||
/// The default is the file where `precondition(_:_:file:line:)` is | ||
/// called. | ||
/// - line: The line number to print along with `message` if the assertion | ||
/// fails. The default is the line number where | ||
/// `precondition(_:_:file:line:)` is called. | ||
@_transparent | ||
public func precondition( | ||
_ condition: @autoclosure () -> Bool, | ||
file: StaticString = #file, line: UInt = #line | ||
) { | ||
// Only check in debug and release mode. In release mode just trap. | ||
if _isDebugAssertConfiguration() { | ||
if !_fastPath(condition()) { | ||
_assertionFailure("Precondition failed", String(), file: file, line: line, | ||
flags: _fatalErrorFlags()) | ||
} | ||
} else if _isReleaseAssertConfiguration() { | ||
let error = !condition() | ||
Builtin.condfail_message(error._value, | ||
StaticString("precondition failure").unsafeRawPointer) | ||
StaticString("Precondition failed").unsafeRawPointer) | ||
} | ||
} | ||
|
||
|
@@ -146,10 +193,10 @@ public func assertionFailure( | |
/// | ||
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug | ||
/// configuration), stops program execution in a debuggable state after | ||
/// printing `message`. | ||
/// printing `message` along with the file and line information. | ||
/// | ||
/// * In `-O` builds (the default for Xcode's Release configuration), stops | ||
/// program execution. | ||
/// program execution after printing `message`. | ||
/// | ||
/// * In `-Ounchecked` builds, the optimizer may assume that this function is | ||
/// never called. Failure to satisfy that assumption is a serious | ||
|
@@ -164,16 +211,53 @@ public func assertionFailure( | |
/// line number where `preconditionFailure(_:file:line:)` is called. | ||
@_transparent | ||
public func preconditionFailure( | ||
_ message: @autoclosure () -> String = String(), | ||
_ message: @autoclosure () -> String, | ||
file: StaticString = #file, line: UInt = #line | ||
) -> Never { | ||
// Only check in debug and release mode. In release mode just trap. | ||
if _isDebugAssertConfiguration() { | ||
_assertionFailure("Fatal error", message(), file: file, line: line, | ||
flags: _fatalErrorFlags()) | ||
} else if _isReleaseAssertConfiguration() { | ||
_assertionFailure("Precondition failed", message(), | ||
flags: _fatalErrorFlags()) | ||
} | ||
_conditionallyUnreachable() | ||
} | ||
|
||
/// Indicates that a precondition was violated, without a message. | ||
/// | ||
/// Use this function to stop the program when control flow can only reach the | ||
/// call if your API was improperly used. This function's effects vary | ||
/// depending on the build flag used: | ||
/// | ||
/// * In playgrounds and `-Onone` builds (the default for Xcode's Debug | ||
/// configuration), stops program execution in a debuggable state after | ||
/// printing "Fatal error". | ||
/// | ||
/// * In `-O` builds (the default for Xcode's Release configuration), stops | ||
/// program execution. | ||
/// | ||
/// * In `-Ounchecked` builds, the optimizer may assume that this function is | ||
/// never called. Failure to satisfy that assumption is a serious | ||
/// programming error. | ||
/// | ||
/// - Parameters: | ||
/// - file: The file name to print with `message`. The default is the file | ||
/// where `preconditionFailure(file:line:)` is called. | ||
/// - line: The line number to print. The default is the | ||
/// line number where `preconditionFailure(file:line:)` is called. | ||
@_transparent | ||
public func preconditionFailure( | ||
file: StaticString = #file, line: UInt = #line | ||
) -> Never { | ||
// Only check in debug and release mode. In release mode just trap. | ||
if _isDebugAssertConfiguration() { | ||
_assertionFailure("Fatal error", String(), file: file, line: line, | ||
flags: _fatalErrorFlags()) | ||
} else if _isReleaseAssertConfiguration() { | ||
Builtin.condfail_message(true._value, | ||
StaticString("precondition failure").unsafeRawPointer) | ||
StaticString("Precondition failed").unsafeRawPointer) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest not adding this additional overload. We don't really want people omitting messages from their preconditions to save on code size; that is an unnecessary level of flexibility. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't add it, but converted the default-argument version to a separate function. Removing the overload would be a source compatibility break. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, I'm saying you could just leave the default-argument version. |
||
} | ||
_conditionallyUnreachable() | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.