fix handling of large indices in SmallProjectionPath

* Fix the right shift operator which didn't work if the number of bits is exactly 64
* Detect overflow when combining indices

Such large indices usually don't appear in real code, except in internal String operations where (potentially large) integer values are treated as pointers.

Fixes a compiler crash
https://github.com/swiftlang/swift/issues/84372
rdar://160863199
This commit is contained in:
Erik Eckstein
2025-09-22 18:48:16 +02:00
parent 9016636714
commit 00f83dd85b

View File

@@ -186,7 +186,7 @@ public struct SmallProjectionPath : Hashable, CustomStringConvertible, NoReflect
/// Pops \p numBits from the path.
private func pop(numBits: Int) -> SmallProjectionPath {
return Self(bytes: bytes &>> numBits)
return Self(bytes: bytes >> numBits)
}
/// Pops and returns the first path component included the resulting path
@@ -210,7 +210,7 @@ public struct SmallProjectionPath : Hashable, CustomStringConvertible, NoReflect
// Ignore zero indices
return self
}
if k == .indexedElement {
if k == .indexedElement && index &+ i >= 0 {
// "Merge" two constant successive indexed elements
return pop(numBits: numBits).push(.indexedElement, index: index + i)
}
@@ -663,7 +663,8 @@ extension SmallProjectionPath {
overlapping()
predicates()
path2path()
indexedElements()
func basicPushPop() {
let p1 = SmallProjectionPath(.structField, index: 3)
.push(.classField, index: 12345678)
@@ -925,5 +926,23 @@ extension SmallProjectionPath {
assert(result == nil)
}
}
func indexedElements() {
let p1 = SmallProjectionPath(.indexedElement, index: 1)
let (k1, i1, s1) = p1.pop()
assert(k1 == .indexedElement && i1 == 1 && s1.isEmpty)
let p2 = SmallProjectionPath(.indexedElement, index: -1)
let (k2, _, s2) = p2.pop()
assert(k2 == .anything && s2.isEmpty)
let p3 = SmallProjectionPath(.indexedElement, index: 0xfffffffffffff)
let (k3, i3, s3) = p3.pop()
assert(k3 == .indexedElement && i3 == 0xfffffffffffff && s3.isEmpty)
let p4 = p3.push(.indexedElement, index: Int.max)
let (k4, _, s4) = p4.pop()
assert(k4 == .anyIndexedElement && s4.isEmpty)
}
}
}