lim.min = c
lim.max = c
}
+ if lim.min >= 0 {
+ // int(x) >= 0 && int(x) >= N ⇒ uint(x) >= N
+ lim.umin = uint64(lim.min)
+ }
+ if lim.max != noLimit.max && old.min >= 0 && lim.max >= 0 {
+ // 0 <= int(x) <= N ⇒ 0 <= uint(x) <= N
+ // This is for a max update, so the lower bound
+ // comes from what we already know (old).
+ lim.umax = uint64(lim.max)
+ }
case unsigned:
var uc uint64
switch w.Op {
lim.umin = uc
lim.umax = uc
}
+ // We could use the contrapositives of the
+ // signed implications to derive signed facts,
+ // but it turns out not to matter.
}
ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
lim = old.intersect(lim)
// Test constant argument to slicemask.
useSlice(b[2:8]) // ERROR "Proved slicemask not needed$"
// Test non-constant argument with known limits.
- // Right now prove only uses the unsigned limit.
- if uint(cap(b)) > 10 {
+ if cap(b) > 10 {
useSlice(b[2:]) // ERROR "Proved slicemask not needed$"
}
}
+func lim1(x, y, z int) {
+ // Test relations between signed and unsigned limits.
+ if x > 5 {
+ if uint(x) > 5 { // ERROR "Proved Greater64U$"
+ return
+ }
+ }
+ if y >= 0 && y < 4 {
+ if uint(y) > 4 { // ERROR "Disproved Greater64U$"
+ return
+ }
+ if uint(y) < 5 { // ERROR "Proved Less64U$"
+ return
+ }
+ }
+ if z < 4 {
+ if uint(z) > 4 { // Not provable without disjunctions.
+ return
+ }
+ }
+}
+
//go:noinline
func useInt(a int) {
}