Skip to content

Commit e01a294

Browse files
committed
[stdlib] Introduce _invariantCheck_5_1 for 5.1 and later assertions.
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.
1 parent 37db587 commit e01a294

File tree

4 files changed

+23
-7
lines changed

4 files changed

+23
-7
lines changed

stdlib/public/core/Assert.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ public func _overflowChecked<T>(
236236
let (result, error) = args
237237
if _isDebugAssertConfiguration() {
238238
if _slowPath(error) {
239-
_fatalErrorMessage("Fatal error", "Overflow/underflow",
239+
_fatalErrorMessage("Fatal error", "Overflow/underflow",
240240
file: file, line: line, flags: _fatalErrorFlags())
241241
}
242242
} else {
@@ -297,6 +297,22 @@ internal func _internalInvariant(
297297
#endif
298298
}
299299

300+
// Only perform the invariant check on Swift 5.1 and later
301+
@_alwaysEmitIntoClient // Swift 5.1
302+
@_transparent
303+
internal func _internalInvariant_5_1(
304+
_ condition: @autoclosure () -> Bool, _ message: StaticString = StaticString(),
305+
file: StaticString = #file, line: UInt = #line
306+
) {
307+
#if INTERNAL_CHECKS_ENABLED
308+
// FIXME: The below won't run the assert on 5.1 stdlib if testing on older
309+
// OSes, which means that testing may not test the assertion. We need a real
310+
// solution to this.
311+
guard #available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) else { return }
312+
_internalInvariant(condition(), message, file: file, line: line)
313+
#endif
314+
}
315+
300316
@usableFromInline @_transparent
301317
internal func _internalInvariantFailure(
302318
_ message: StaticString = StaticString(),

stdlib/public/core/StringCharacterView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ extension String: BidirectionalCollection {
201201

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

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

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

218218
if i == startIndex { return 0 }
219219

stdlib/public/core/StringIndex.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ extension String.Index {
164164
internal func _invariantCheck() {
165165
_internalInvariant(_encodedOffset >= 0)
166166
if self._isScalarAligned {
167-
_internalInvariant(transcodedOffset == 0)
167+
_internalInvariant_5_1(transcodedOffset == 0)
168168
}
169169
}
170170
#endif // INTERNAL_CHECKS_ENABLED

stdlib/public/core/UnicodeHelpers.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,22 +172,22 @@ extension _StringGuts {
172172

173173
_internalInvariant(isOnUnicodeScalarBoundary(result),
174174
"Alignment bit is set for non-aligned index")
175-
_internalInvariant(result._isScalarAligned)
175+
_internalInvariant_5_1(result._isScalarAligned)
176176
return result
177177
}
178178

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

184184
if _slowPath(idx.transcodedOffset != 0 || idx._encodedOffset == 0) {
185185
// Transcoded index offsets are already scalar aligned
186186
return String.Index(_encodedOffset: idx._encodedOffset)._scalarAligned
187187
}
188188
if _slowPath(self.isForeign) {
189189
let foreignIdx = foreignScalarAlign(idx)
190-
_internalInvariant(foreignIdx._isScalarAligned)
190+
_internalInvariant_5_1(foreignIdx._isScalarAligned)
191191
return foreignIdx
192192
}
193193

0 commit comments

Comments
 (0)