The -Ounchecked
compiler mode treats runtime overflows as if they were preconditions that well-formed code would always avoid. This is almost universally not the case, and it shouldn’t disable them.
A separate flag for disabling overflow checks and only overflow checks could be added to replace it, such that current behavior could be trivially replicated by combining the two flags.
Motivation
Swift prioritizes safety, in the sense of avoiding undefined behavior, whenever possible. This is implemented through a hierarchy of mistakes and errors (not to be confused with thrown errors, which are actually business as usual):
- Compile-time errors (checked during compilation)
- Assertion failures (checked during debug runs)
- Precondition failures (checked during standard
-O
runs) - Fatal errors (checked during all runs)
Of these, the first three are only encountered in code that is incorrect. Were it not for technical limitations and other practical issues, all of them would be compile-time checked. To quote Swift’s documentation:
Failure to satisfy that assumption is a serious programming error.
If code is written correctly all of the first three checks are redundant. Anyone wishing to maximize runtime efficiency, therefore, could consider using -Ounchecked
.
In practice, few use that compiler mode right now, as there is an exception to that model that causes -Ounchecked
code to risk undefined behavior even if there are literally no programming errors: integer overflow checking.
Arithmetic operators in Swift do not have preconditions stating that the result must not overflow, and few explicitly check for overflow before using them. Furthermore, architecture-dependent typealiases like Int
are basically impossible to use without theoretically risking overflow.
Overflow is an issue that cannot be ruled out, but is also not worth recovering from or working around[1]. This makes its position in the error hierarchy clear: #4, fatal error.
Proposed Solution
Overflow checking should be treated like a fatal error, not a precondition. This means that it is kept regardless of optimization mode.
Precondition checks, such as accessing an Array with an invalid index, would continue to be eliminated.
Effect on ABI stability
None, as code that is already compiled would be unaffected.
Effect on API resilience
Minimal: Any documentation that states overflow checks are not performed in -Ounchecked
builds would need to be updated, but no interface would be changed and it is unlikely to affect almost any usage of these operators.
Future Directions
In the interest of preserving the current meaning, undefined behavior and all, for those who prefer it, it may be worth adding an additional compiler flag that toggles overflow checks and only overflow checks. This could be used in combination with any optimization mode, with the caveat that the resulting binary cannot be considered an accurate representation of the original Swift code.
If a programmer wanted to handle overflow, they'd be using the methods that actually report it. ↩︎