Skip to content

Commit 077a01f

Browse files
authored
Merge pull request #79813 from glessard/unchecked-bounds-are-unsafe
[stdlib] Unchecked bounds are unsafe
2 parents 30be52d + dfb2e2f commit 077a01f

14 files changed

+60
-44
lines changed

stdlib/public/core/ClosedRange.swift

+11-6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public struct ClosedRange<Bound: Comparable> {
7070

7171
// This works around _debugPrecondition() impacting the performance of
7272
// optimized code. (rdar://72246338)
73+
@unsafe
7374
@_alwaysEmitIntoClient @inline(__always)
7475
internal init(_uncheckedBounds bounds: (lower: Bound, upper: Bound)) {
7576
self.lowerBound = bounds.lower
@@ -89,7 +90,9 @@ public struct ClosedRange<Bound: Comparable> {
8990
public init(uncheckedBounds bounds: (lower: Bound, upper: Bound)) {
9091
_debugPrecondition(bounds.lower <= bounds.upper,
9192
"ClosedRange requires lowerBound <= upperBound")
92-
self.init(_uncheckedBounds: (lower: bounds.lower, upper: bounds.upper))
93+
unsafe self.init(
94+
_uncheckedBounds: (lower: bounds.lower, upper: bounds.upper)
95+
)
9396
}
9497
}
9598

@@ -109,7 +112,7 @@ extension ClosedRange: RangeExpression {
109112
@inlinable // trivial-implementation
110113
public func relative<C: Collection>(to collection: C) -> Range<Bound>
111114
where C.Index == Bound {
112-
return Range(
115+
return unsafe Range(
113116
_uncheckedBounds: (
114117
lower: lowerBound,
115118
upper: collection.index(after: self.upperBound)))
@@ -405,7 +408,7 @@ extension Comparable {
405408
public static func ... (minimum: Self, maximum: Self) -> ClosedRange<Self> {
406409
_precondition(
407410
minimum <= maximum, "Range requires lowerBound <= upperBound")
408-
return ClosedRange(_uncheckedBounds: (lower: minimum, upper: maximum))
411+
return unsafe ClosedRange(_uncheckedBounds: (lower: minimum, upper: maximum))
409412
}
410413
}
411414

@@ -496,7 +499,7 @@ extension ClosedRange {
496499
limits.upperBound < self.upperBound ? limits.upperBound
497500
: limits.lowerBound > self.upperBound ? limits.lowerBound
498501
: self.upperBound
499-
return ClosedRange(_uncheckedBounds: (lower: lower, upper: upper))
502+
return unsafe ClosedRange(_uncheckedBounds: (lower: lower, upper: upper))
500503
}
501504
}
502505

@@ -512,7 +515,9 @@ extension ClosedRange where Bound: Strideable, Bound.Stride: SignedInteger {
512515
public init(_ other: Range<Bound>) {
513516
_precondition(!other.isEmpty, "Can't form an empty closed range")
514517
let upperBound = other.upperBound.advanced(by: -1)
515-
self.init(_uncheckedBounds: (lower: other.lowerBound, upper: upperBound))
518+
unsafe self.init(
519+
_uncheckedBounds: (lower: other.lowerBound, upper: upperBound)
520+
)
516521
}
517522
}
518523

@@ -581,7 +586,7 @@ extension ClosedRange: Decodable where Bound: Decodable {
581586
codingPath: decoder.codingPath,
582587
debugDescription: "Cannot initialize \(ClosedRange.self) with a lowerBound (\(lowerBound)) greater than upperBound (\(upperBound))"))
583588
}
584-
self.init(_uncheckedBounds: (lower: lowerBound, upper: upperBound))
589+
unsafe self.init(_uncheckedBounds: (lower: lowerBound, upper: upperBound))
585590
}
586591
}
587592

stdlib/public/core/InlineArray.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ extension InlineArray where Element: ~Copyable {
294294
@_alwaysEmitIntoClient
295295
@_transparent
296296
public var indices: Range<Int> {
297-
Range(_uncheckedBounds: (0, count))
297+
unsafe Range(_uncheckedBounds: (0, count))
298298
}
299299

300300
/// Returns the position immediately after the given index.

stdlib/public/core/Range.swift

+11-6
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ public struct Range<Bound: Comparable> {
159159

160160
// This works around _debugPrecondition() impacting the performance of
161161
// optimized code. (rdar://72246338)
162+
@unsafe
162163
@_alwaysEmitIntoClient @inline(__always)
163164
internal init(_uncheckedBounds bounds: (lower: Bound, upper: Bound)) {
164165
self.lowerBound = bounds.lower
@@ -178,7 +179,9 @@ public struct Range<Bound: Comparable> {
178179
public init(uncheckedBounds bounds: (lower: Bound, upper: Bound)) {
179180
_debugPrecondition(bounds.lower <= bounds.upper,
180181
"Range requires lowerBound <= upperBound")
181-
self.init(_uncheckedBounds: (lower: bounds.lower, upper: bounds.upper))
182+
unsafe self.init(
183+
_uncheckedBounds: (lower: bounds.lower, upper: bounds.upper)
184+
)
182185
}
183186

184187
/// Returns a Boolean value indicating whether the given element is contained
@@ -321,7 +324,9 @@ extension Range where Bound: Strideable, Bound.Stride: SignedInteger {
321324
@inlinable // trivial-implementation
322325
public init(_ other: ClosedRange<Bound>) {
323326
let upperBound = other.upperBound.advanced(by: 1)
324-
self.init(_uncheckedBounds: (lower: other.lowerBound, upper: upperBound))
327+
unsafe self.init(
328+
_uncheckedBounds: (lower: other.lowerBound, upper: upperBound)
329+
)
325330
}
326331
}
327332

@@ -372,7 +377,7 @@ extension Range {
372377
limits.upperBound < self.upperBound ? limits.upperBound
373378
: limits.lowerBound > self.upperBound ? limits.lowerBound
374379
: self.upperBound
375-
return Range(_uncheckedBounds: (lower: lower, upper: upper))
380+
return unsafe Range(_uncheckedBounds: (lower: lower, upper: upper))
376381
}
377382
}
378383

@@ -453,7 +458,7 @@ extension Range: Decodable where Bound: Decodable {
453458
codingPath: decoder.codingPath,
454459
debugDescription: "Cannot initialize \(Range.self) with a lowerBound (\(lowerBound)) greater than upperBound (\(upperBound))"))
455460
}
456-
self.init(_uncheckedBounds: (lower: lowerBound, upper: upperBound))
461+
unsafe self.init(_uncheckedBounds: (lower: lowerBound, upper: upperBound))
457462
}
458463
}
459464

@@ -754,7 +759,7 @@ extension Comparable {
754759
public static func ..< (minimum: Self, maximum: Self) -> Range<Self> {
755760
_precondition(minimum <= maximum,
756761
"Range requires lowerBound <= upperBound")
757-
return Range(_uncheckedBounds: (lower: minimum, upper: maximum))
762+
return unsafe Range(_uncheckedBounds: (lower: minimum, upper: maximum))
758763
}
759764

760765
/// Returns a partial range up to, but not including, its upper bound.
@@ -1123,7 +1128,7 @@ extension Range where Bound == String.Index {
11231128
_internalInvariant(
11241129
(lowerBound._canBeUTF8 && upperBound._canBeUTF8)
11251130
|| (lowerBound._canBeUTF16 && upperBound._canBeUTF16))
1126-
return Range<Int>(
1131+
return unsafe Range<Int>(
11271132
_uncheckedBounds: (lowerBound._encodedOffset, upperBound._encodedOffset))
11281133
}
11291134
}

stdlib/public/core/Slice.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public struct Slice<Base: Collection> {
138138

139139
@_alwaysEmitIntoClient @inline(__always)
140140
internal var _bounds: Range<Base.Index> {
141-
Range(_uncheckedBounds: (_startIndex, _endIndex))
141+
unsafe Range(_uncheckedBounds: (_startIndex, _endIndex))
142142
}
143143
}
144144

stdlib/public/core/Span/RawSpan.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ extension RawSpan {
322322
/// - Complexity: O(1)
323323
@_alwaysEmitIntoClient
324324
public var byteOffsets: Range<Int> {
325-
.init(_uncheckedBounds: (0, byteCount))
325+
unsafe Range(_uncheckedBounds: (0, byteCount))
326326
}
327327
}
328328

@@ -629,13 +629,13 @@ extension RawSpan {
629629
public func byteOffsets(of other: borrowing Self) -> Range<Int>? {
630630
if other._count > _count { return nil }
631631
guard let spanStart = other._pointer, _count > 0 else {
632-
return unsafe _pointer == other._pointer ? Range(_uncheckedBounds: (0, 0)) : nil
632+
return unsafe _pointer == other._pointer ? 0..<0 : nil
633633
}
634634
let start = _start()
635635
let spanEnd = unsafe spanStart + other._count
636636
if unsafe spanStart < start || (start + _count) < spanEnd { return nil }
637637
let lower = unsafe start.distance(to: spanStart)
638-
return Range(_uncheckedBounds: (lower, lower &+ other._count))
638+
return unsafe Range(_uncheckedBounds: (lower, lower &+ other._count))
639639
}
640640
}
641641

stdlib/public/core/Span/Span.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ extension Span where Element: ~Copyable {
395395
/// - Complexity: O(1)
396396
@_alwaysEmitIntoClient
397397
public var indices: Range<Index> {
398-
Range(_uncheckedBounds: (0, _count))
398+
unsafe Range(_uncheckedBounds: (0, _count))
399399
}
400400
}
401401

@@ -679,7 +679,7 @@ extension Span where Element: ~Copyable {
679679
public func indices(of other: borrowing Self) -> Range<Index>? {
680680
if other._count > _count { return nil }
681681
guard let spanStart = other._pointer, _count > 0 else {
682-
return unsafe _pointer == other._pointer ? Range(_uncheckedBounds: (0, 0)) : nil
682+
return unsafe _pointer == other._pointer ? 0..<0 : nil
683683
}
684684
let start = _start()
685685
let stride = MemoryLayout<Element>.stride
@@ -688,7 +688,7 @@ extension Span where Element: ~Copyable {
688688
let byteOffset = unsafe start.distance(to: spanStart)
689689
let (lower, r) = byteOffset.quotientAndRemainder(dividingBy: stride)
690690
guard r == 0 else { return nil }
691-
return Range(_uncheckedBounds: (lower, lower &+ other._count))
691+
return unsafe Range(_uncheckedBounds: (lower, lower &+ other._count))
692692
}
693693
}
694694

stdlib/public/core/StringGraphemeBreaking.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ extension Unicode {
599599
while i < buffer.endIndex {
600600
let (next, n) = unsafe _decodeScalar(buffer, startingAt: i)
601601
if hasBreak(before: next) {
602-
return Range(_uncheckedBounds: (i, i &+ n))
602+
return unsafe Range(_uncheckedBounds: (i, i &+ n))
603603
}
604604
i &+= n
605605
}

stdlib/public/core/StringGutsRangeReplaceable.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ extension _StringGuts {
367367
let j = result._guts.count
368368
result.append(contentsOf: selfStr[bounds.upperBound...])
369369
self = result._guts
370-
return Range(_uncheckedBounds: (i, j))
370+
return unsafe Range(_uncheckedBounds: (i, j))
371371
}
372372

373373
// - Returns: The encoded offset range of the replaced contents in the result.
@@ -421,7 +421,7 @@ extension _StringGuts {
421421
let j = result._guts.count
422422
result.append(contentsOf: selfStr[bounds.upperBound...])
423423
self = result._guts
424-
return Range(_uncheckedBounds: (i, j))
424+
return unsafe Range(_uncheckedBounds: (i, j))
425425
}
426426

427427
// - Returns: The encoded offset range of the replaced contents in the result.
@@ -443,7 +443,7 @@ extension _StringGuts {
443443
updateNativeStorage {
444444
unsafe $0.replace(from: start, to: end, with: codeUnits)
445445
}
446-
return Range(_uncheckedBounds: (start, start + codeUnits.count))
446+
return unsafe Range(_uncheckedBounds: (start, start + codeUnits.count))
447447
}
448448

449449
// - Returns: The encoded offset range of the replaced contents in the result.
@@ -468,7 +468,7 @@ extension _StringGuts {
468468
$0.replace(
469469
from: start, to: end, with: codeUnits, replacementCount: replCount)
470470
}
471-
return Range(_uncheckedBounds: (start, start + replCount))
471+
return unsafe Range(_uncheckedBounds: (start, start + replCount))
472472
}
473473

474474
/// Run `body` to mutate the given `subrange` of this string within
@@ -540,9 +540,9 @@ extension _StringGuts {
540540
let oldRange = subrange._encodedOffsetRange
541541
let newRange = body(&self)
542542

543-
let oldBounds = Range(
543+
let oldBounds = unsafe Range(
544544
_uncheckedBounds: (startIndex._encodedOffset, endIndex._encodedOffset))
545-
let newBounds = Range(_uncheckedBounds: (
545+
let newBounds = unsafe Range(_uncheckedBounds: (
546546
oldBounds.lowerBound,
547547
oldBounds.upperBound &+ newRange.count &- oldRange.count))
548548

stdlib/public/core/StringGutsSlice.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ internal struct _StringGutsSlice {
2424
@inline(__always)
2525
internal init(_ guts: _StringGuts) {
2626
self._guts = guts
27-
self._offsetRange = Range(_uncheckedBounds: (0, guts.count))
27+
self._offsetRange = unsafe Range(_uncheckedBounds: (0, guts.count))
2828
}
2929

3030
@inline(__always)
@@ -74,7 +74,7 @@ internal struct _StringGutsSlice {
7474
._scalarAligned
7575
let higher = String.Index(_encodedOffset: _offsetRange.upperBound)
7676
._scalarAligned
77-
return Range(_uncheckedBounds: (lower, higher))
77+
return unsafe Range(_uncheckedBounds: (lower, higher))
7878
}
7979
}
8080

stdlib/public/core/StringIndexValidation.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ extension _StringGuts {
8080
_precondition(upper <= endIndex && lower <= upper,
8181
"String index range is out of bounds")
8282

83-
return Range(_uncheckedBounds: (lower, upper))
83+
return unsafe Range(_uncheckedBounds: (lower, upper))
8484
}
8585

8686
@_alwaysEmitIntoClient
@@ -102,7 +102,7 @@ extension _StringGuts {
102102
&& upper <= bounds.upperBound,
103103
"Substring index range is out of bounds")
104104

105-
return Range(_uncheckedBounds: (lower, upper))
105+
return unsafe Range(_uncheckedBounds: (lower, upper))
106106
}
107107
}
108108

@@ -213,7 +213,7 @@ extension _StringGuts {
213213
}
214214

215215
let r = validateSubscalarRange(range)
216-
return Range(
216+
return unsafe Range(
217217
_uncheckedBounds: (scalarAlign(r.lowerBound), scalarAlign(r.upperBound)))
218218
}
219219

@@ -243,7 +243,7 @@ extension _StringGuts {
243243
let r = validateSubscalarRange(range, in: bounds)
244244
let upper = scalarAlign(r.upperBound)
245245
let lower = scalarAlign(r.lowerBound)
246-
return Range(_uncheckedBounds: (lower, upper))
246+
return unsafe Range(_uncheckedBounds: (lower, upper))
247247
}
248248
}
249249

@@ -356,7 +356,7 @@ extension _StringGuts {
356356
_precondition(upper <= endIndex && lower <= upper,
357357
"String index range is out of bounds")
358358

359-
return Range(_uncheckedBounds: (lower, upper))
359+
return unsafe Range(_uncheckedBounds: (lower, upper))
360360
}
361361

362362
/// A version of `validateScalarRange` that only traps if the main executable
@@ -377,7 +377,7 @@ extension _StringGuts {
377377
}
378378

379379
let r = validateSubscalarRange_5_7(range)
380-
return Range(
380+
return unsafe Range(
381381
_uncheckedBounds: (scalarAlign(r.lowerBound), scalarAlign(r.upperBound)))
382382
}
383383

stdlib/public/core/StringProtocol.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ extension StringProtocol {
153153
let end = endIndex
154154
_internalInvariant(
155155
start.transcodedOffset == 0 && end.transcodedOffset == 0)
156-
return Range(_uncheckedBounds: (start._encodedOffset, end._encodedOffset))
156+
return unsafe Range(
157+
_uncheckedBounds: (start._encodedOffset, end._encodedOffset)
158+
)
157159
}
158160
}
159161

stdlib/public/core/StringRangeReplaceableCollection.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ extension String: RangeReplaceableCollection {
218218
/// - Complexity: O(*n*), where *n* is the length of the string.
219219
public mutating func insert(_ newElement: Character, at i: Index) {
220220
let i = _guts.validateInclusiveScalarIndex(i)
221-
let range = Range(_uncheckedBounds: (i, i))
221+
let range = unsafe Range(_uncheckedBounds: (i, i))
222222
_guts.replaceSubrange(range, with: newElement._str)
223223
}
224224

@@ -243,7 +243,7 @@ extension String: RangeReplaceableCollection {
243243
contentsOf newElements: S, at i: Index
244244
) where S.Element == Character {
245245
let i = _guts.validateInclusiveScalarIndex(i)
246-
let range = Range(_uncheckedBounds: (i, i))
246+
let range = unsafe Range(_uncheckedBounds: (i, i))
247247
_guts.replaceSubrange(range, with: newElements)
248248
}
249249

stdlib/public/core/StringStorageBridge.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ extension _AbstractStringStorage {
5454
_precondition(aRange.location + aRange.length <= Int(count),
5555
"Range out of bounds")
5656

57-
let range = Range(
57+
let range = unsafe Range(
5858
_uncheckedBounds: (aRange.location, aRange.location+aRange.length))
5959
let str = asString
6060
unsafe str._copyUTF16CodeUnits(

0 commit comments

Comments
 (0)