Skip to content

Commit

Permalink
[stdlib] Introduce _invariantCheck_5_1 for 5.1 and later assertions.
Browse files Browse the repository at this point in the history
Inlinable and non-inlinable code can cause 5.1 code to intermix with
5.0 code on older OSes. Some (weak) invariants for 5.1 should only be
checked when the OS's code is 5.1 or later, which is the purpose of
_invariantCheck_5_1.

Applied to String.Index._isScalarAligned, which is a new bit
introduced in 5.1 from one of the reserved bits from 5.0. The bit is
set when the index is proven to be scalar aligned, and we want to
assert on this liberally in contexts where we expect it to be
so. However, older OSes might not set this bit when doing scalar
aligning, depending on exactly what got inlined where/when.
  • Loading branch information
milseman committed Jul 12, 2019
1 parent 37db587 commit e01a294
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 7 deletions.
18 changes: 17 additions & 1 deletion stdlib/public/core/Assert.swift
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public func _overflowChecked<T>(
let (result, error) = args
if _isDebugAssertConfiguration() {
if _slowPath(error) {
_fatalErrorMessage("Fatal error", "Overflow/underflow",
_fatalErrorMessage("Fatal error", "Overflow/underflow",
file: file, line: line, flags: _fatalErrorFlags())
}
} else {
Expand Down Expand Up @@ -297,6 +297,22 @@ internal func _internalInvariant(
#endif
}

// Only perform the invariant check on Swift 5.1 and later
@_alwaysEmitIntoClient // Swift 5.1
@_transparent
internal func _internalInvariant_5_1(
_ condition: @autoclosure () -> Bool, _ message: StaticString = StaticString(),
file: StaticString = #file, line: UInt = #line
) {
#if INTERNAL_CHECKS_ENABLED
// FIXME: The below won't run the assert on 5.1 stdlib if testing on older
// OSes, which means that testing may not test the assertion. We need a real
// solution to this.
guard #available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) else { return }
_internalInvariant(condition(), message, file: file, line: line)
#endif
}

@usableFromInline @_transparent
internal func _internalInvariantFailure(
_ message: StaticString = StaticString(),
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/core/StringCharacterView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ extension String: BidirectionalCollection {

@inlinable @inline(__always)
internal func _characterStride(startingAt i: Index) -> Int {
_internalInvariant(i._isScalarAligned)
_internalInvariant_5_1(i._isScalarAligned)

// Fast check if it's already been measured, otherwise check resiliently
if let d = i.characterStride { return d }
Expand All @@ -213,7 +213,7 @@ extension String: BidirectionalCollection {

@inlinable @inline(__always)
internal func _characterStride(endingAt i: Index) -> Int {
_internalInvariant(i._isScalarAligned)
_internalInvariant_5_1(i._isScalarAligned)

if i == startIndex { return 0 }

Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/core/StringIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ extension String.Index {
internal func _invariantCheck() {
_internalInvariant(_encodedOffset >= 0)
if self._isScalarAligned {
_internalInvariant(transcodedOffset == 0)
_internalInvariant_5_1(transcodedOffset == 0)
}
}
#endif // INTERNAL_CHECKS_ENABLED
Expand Down
6 changes: 3 additions & 3 deletions stdlib/public/core/UnicodeHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,22 +172,22 @@ extension _StringGuts {

_internalInvariant(isOnUnicodeScalarBoundary(result),
"Alignment bit is set for non-aligned index")
_internalInvariant(result._isScalarAligned)
_internalInvariant_5_1(result._isScalarAligned)
return result
}

@inline(never) // slow-path
@_alwaysEmitIntoClient // Swift 5.1
internal func scalarAlignSlow(_ idx: Index) -> Index {
_internalInvariant(!idx._isScalarAligned)
_internalInvariant_5_1(!idx._isScalarAligned)

if _slowPath(idx.transcodedOffset != 0 || idx._encodedOffset == 0) {
// Transcoded index offsets are already scalar aligned
return String.Index(_encodedOffset: idx._encodedOffset)._scalarAligned
}
if _slowPath(self.isForeign) {
let foreignIdx = foreignScalarAlign(idx)
_internalInvariant(foreignIdx._isScalarAligned)
_internalInvariant_5_1(foreignIdx._isScalarAligned)
return foreignIdx
}

Expand Down

0 comments on commit e01a294

Please sign in to comment.