]> Cypherpunks.ru repositories - gostls13.git/blob - test/prove.go
cmd/compile: reverse order of slice bounds checks
[gostls13.git] / test / prove.go
1 // +build amd64
2 // errorcheck -0 -d=ssa/prove/debug=1
3
4 // Copyright 2016 The Go Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file.
7
8 package main
9
10 import "math"
11
12 func f0(a []int) int {
13         a[0] = 1
14         a[0] = 1 // ERROR "Proved IsInBounds$"
15         a[6] = 1
16         a[6] = 1 // ERROR "Proved IsInBounds$"
17         a[5] = 1 // ERROR "Proved IsInBounds$"
18         a[5] = 1 // ERROR "Proved IsInBounds$"
19         return 13
20 }
21
22 func f1(a []int) int {
23         if len(a) <= 5 {
24                 return 18
25         }
26         a[0] = 1 // ERROR "Proved IsInBounds$"
27         a[0] = 1 // ERROR "Proved IsInBounds$"
28         a[6] = 1
29         a[6] = 1 // ERROR "Proved IsInBounds$"
30         a[5] = 1 // ERROR "Proved IsInBounds$"
31         a[5] = 1 // ERROR "Proved IsInBounds$"
32         return 26
33 }
34
35 func f1b(a []int, i int, j uint) int {
36         if i >= 0 && i < len(a) {
37                 return a[i] // ERROR "Proved IsInBounds$"
38         }
39         if i >= 10 && i < len(a) {
40                 return a[i] // ERROR "Proved IsInBounds$"
41         }
42         if i >= 10 && i < len(a) {
43                 return a[i] // ERROR "Proved IsInBounds$"
44         }
45         if i >= 10 && i < len(a) {
46                 return a[i-10] // ERROR "Proved IsInBounds$"
47         }
48         if j < uint(len(a)) {
49                 return a[j] // ERROR "Proved IsInBounds$"
50         }
51         return 0
52 }
53
54 func f1c(a []int, i int64) int {
55         c := uint64(math.MaxInt64 + 10) // overflows int
56         d := int64(c)
57         if i >= d && i < int64(len(a)) {
58                 // d overflows, should not be handled.
59                 return a[i]
60         }
61         return 0
62 }
63
64 func f2(a []int) int {
65         for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
66                 a[i+1] = i
67                 a[i+1] = i // ERROR "Proved IsInBounds$"
68         }
69         return 34
70 }
71
72 func f3(a []uint) int {
73         for i := uint(0); i < uint(len(a)); i++ {
74                 a[i] = i // ERROR "Proved IsInBounds$"
75         }
76         return 41
77 }
78
79 func f4a(a, b, c int) int {
80         if a < b {
81                 if a == b { // ERROR "Disproved Eq64$"
82                         return 47
83                 }
84                 if a > b { // ERROR "Disproved Greater64$"
85                         return 50
86                 }
87                 if a < b { // ERROR "Proved Less64$"
88                         return 53
89                 }
90                 // We can't get to this point and prove knows that, so
91                 // there's no message for the next (obvious) branch.
92                 if a != a {
93                         return 56
94                 }
95                 return 61
96         }
97         return 63
98 }
99
100 func f4b(a, b, c int) int {
101         if a <= b {
102                 if a >= b {
103                         if a == b { // ERROR "Proved Eq64$"
104                                 return 70
105                         }
106                         return 75
107                 }
108                 return 77
109         }
110         return 79
111 }
112
113 func f4c(a, b, c int) int {
114         if a <= b {
115                 if a >= b {
116                         if a != b { // ERROR "Disproved Neq64$"
117                                 return 73
118                         }
119                         return 75
120                 }
121                 return 77
122         }
123         return 79
124 }
125
126 func f4d(a, b, c int) int {
127         if a < b {
128                 if a < c {
129                         if a < b { // ERROR "Proved Less64$"
130                                 if a < c { // ERROR "Proved Less64$"
131                                         return 87
132                                 }
133                                 return 89
134                         }
135                         return 91
136                 }
137                 return 93
138         }
139         return 95
140 }
141
142 func f4e(a, b, c int) int {
143         if a < b {
144                 if b > a { // ERROR "Proved Greater64$"
145                         return 101
146                 }
147                 return 103
148         }
149         return 105
150 }
151
152 func f4f(a, b, c int) int {
153         if a <= b {
154                 if b > a {
155                         if b == a { // ERROR "Disproved Eq64$"
156                                 return 112
157                         }
158                         return 114
159                 }
160                 if b >= a { // ERROR "Proved Geq64$"
161                         if b == a { // ERROR "Proved Eq64$"
162                                 return 118
163                         }
164                         return 120
165                 }
166                 return 122
167         }
168         return 124
169 }
170
171 func f5(a, b uint) int {
172         if a == b {
173                 if a <= b { // ERROR "Proved Leq64U$"
174                         return 130
175                 }
176                 return 132
177         }
178         return 134
179 }
180
181 // These comparisons are compile time constants.
182 func f6a(a uint8) int {
183         if a < a { // ERROR "Disproved Less8U$"
184                 return 140
185         }
186         return 151
187 }
188
189 func f6b(a uint8) int {
190         if a < a { // ERROR "Disproved Less8U$"
191                 return 140
192         }
193         return 151
194 }
195
196 func f6x(a uint8) int {
197         if a > a { // ERROR "Disproved Greater8U$"
198                 return 143
199         }
200         return 151
201 }
202
203 func f6d(a uint8) int {
204         if a <= a { // ERROR "Proved Leq8U$"
205                 return 146
206         }
207         return 151
208 }
209
210 func f6e(a uint8) int {
211         if a >= a { // ERROR "Proved Geq8U$"
212                 return 149
213         }
214         return 151
215 }
216
217 func f7(a []int, b int) int {
218         if b < len(a) {
219                 a[b] = 3
220                 if b < len(a) { // ERROR "Proved Less64$"
221                         a[b] = 5 // ERROR "Proved IsInBounds$"
222                 }
223         }
224         return 161
225 }
226
227 func f8(a, b uint) int {
228         if a == b {
229                 return 166
230         }
231         if a > b {
232                 return 169
233         }
234         if a < b { // ERROR "Proved Less64U$"
235                 return 172
236         }
237         return 174
238 }
239
240 func f9(a, b bool) int {
241         if a {
242                 return 1
243         }
244         if a || b { // ERROR "Disproved Arg$"
245                 return 2
246         }
247         return 3
248 }
249
250 func f10(a string) int {
251         n := len(a)
252         // We optimize comparisons with small constant strings (see cmd/compile/internal/gc/walk.go),
253         // so this string literal must be long.
254         if a[:n>>1] == "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {
255                 return 0
256         }
257         return 1
258 }
259
260 func f11a(a []int, i int) {
261         useInt(a[i])
262         useInt(a[i]) // ERROR "Proved IsInBounds$"
263 }
264
265 func f11b(a []int, i int) {
266         useSlice(a[i:])
267         useSlice(a[i:]) // ERROR "Proved IsSliceInBounds$"
268 }
269
270 func f11c(a []int, i int) {
271         useSlice(a[:i])
272         useSlice(a[:i]) // ERROR "Proved IsSliceInBounds$"
273 }
274
275 func f11d(a []int, i int) {
276         useInt(a[2*i+7])
277         useInt(a[2*i+7]) // ERROR "Proved IsInBounds$"
278 }
279
280 func f12(a []int, b int) {
281         useSlice(a[:b])
282 }
283
284 func f13a(a, b, c int, x bool) int {
285         if a > 12 {
286                 if x {
287                         if a < 12 { // ERROR "Disproved Less64$"
288                                 return 1
289                         }
290                 }
291                 if x {
292                         if a <= 12 { // ERROR "Disproved Leq64$"
293                                 return 2
294                         }
295                 }
296                 if x {
297                         if a == 12 { // ERROR "Disproved Eq64$"
298                                 return 3
299                         }
300                 }
301                 if x {
302                         if a >= 12 { // ERROR "Proved Geq64$"
303                                 return 4
304                         }
305                 }
306                 if x {
307                         if a > 12 { // ERROR "Proved Greater64$"
308                                 return 5
309                         }
310                 }
311                 return 6
312         }
313         return 0
314 }
315
316 func f13b(a int, x bool) int {
317         if a == -9 {
318                 if x {
319                         if a < -9 { // ERROR "Disproved Less64$"
320                                 return 7
321                         }
322                 }
323                 if x {
324                         if a <= -9 { // ERROR "Proved Leq64$"
325                                 return 8
326                         }
327                 }
328                 if x {
329                         if a == -9 { // ERROR "Proved Eq64$"
330                                 return 9
331                         }
332                 }
333                 if x {
334                         if a >= -9 { // ERROR "Proved Geq64$"
335                                 return 10
336                         }
337                 }
338                 if x {
339                         if a > -9 { // ERROR "Disproved Greater64$"
340                                 return 11
341                         }
342                 }
343                 return 12
344         }
345         return 0
346 }
347
348 func f13c(a int, x bool) int {
349         if a < 90 {
350                 if x {
351                         if a < 90 { // ERROR "Proved Less64$"
352                                 return 13
353                         }
354                 }
355                 if x {
356                         if a <= 90 { // ERROR "Proved Leq64$"
357                                 return 14
358                         }
359                 }
360                 if x {
361                         if a == 90 { // ERROR "Disproved Eq64$"
362                                 return 15
363                         }
364                 }
365                 if x {
366                         if a >= 90 { // ERROR "Disproved Geq64$"
367                                 return 16
368                         }
369                 }
370                 if x {
371                         if a > 90 { // ERROR "Disproved Greater64$"
372                                 return 17
373                         }
374                 }
375                 return 18
376         }
377         return 0
378 }
379
380 func f13d(a int) int {
381         if a < 5 {
382                 if a < 9 { // ERROR "Proved Less64$"
383                         return 1
384                 }
385         }
386         return 0
387 }
388
389 func f13e(a int) int {
390         if a > 9 {
391                 if a > 5 { // ERROR "Proved Greater64$"
392                         return 1
393                 }
394         }
395         return 0
396 }
397
398 func f13f(a int64) int64 {
399         if a > math.MaxInt64 {
400                 if a == 0 { // ERROR "Disproved Eq64$"
401                         return 1
402                 }
403         }
404         return 0
405 }
406
407 func f13g(a int) int {
408         if a < 3 {
409                 return 5
410         }
411         if a > 3 {
412                 return 6
413         }
414         if a == 3 { // ERROR "Proved Eq64$"
415                 return 7
416         }
417         return 8
418 }
419
420 func f13h(a int) int {
421         if a < 3 {
422                 if a > 1 {
423                         if a == 2 { // ERROR "Proved Eq64$"
424                                 return 5
425                         }
426                 }
427         }
428         return 0
429 }
430
431 func f13i(a uint) int {
432         if a == 0 {
433                 return 1
434         }
435         if a > 0 { // ERROR "Proved Greater64U$"
436                 return 2
437         }
438         return 3
439 }
440
441 func f14(p, q *int, a []int) {
442         // This crazy ordering usually gives i1 the lowest value ID,
443         // j the middle value ID, and i2 the highest value ID.
444         // That used to confuse CSE because it ordered the args
445         // of the two + ops below differently.
446         // That in turn foiled bounds check elimination.
447         i1 := *p
448         j := *q
449         i2 := *p
450         useInt(a[i1+j])
451         useInt(a[i2+j]) // ERROR "Proved IsInBounds$"
452 }
453
454 func f15(s []int, x int) {
455         useSlice(s[x:])
456         useSlice(s[:x]) // ERROR "Proved IsSliceInBounds$"
457 }
458
459 func f16(s []int) []int {
460         if len(s) >= 10 {
461                 return s[:10] // ERROR "Proved IsSliceInBounds$"
462         }
463         return nil
464 }
465
466 func f17(b []int) {
467         for i := 0; i < len(b); i++ { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
468                 // This tests for i <= cap, which we can only prove
469                 // using the derived relation between len and cap.
470                 // This depends on finding the contradiction, since we
471                 // don't query this condition directly.
472                 useSlice(b[:i]) // ERROR "Proved IsSliceInBounds$"
473         }
474 }
475
476 func f18(b []int, x int, y uint) {
477         _ = b[x]
478         _ = b[y]
479
480         if x > len(b) { // ERROR "Disproved Greater64$"
481                 return
482         }
483         if y > uint(len(b)) { // ERROR "Disproved Greater64U$"
484                 return
485         }
486         if int(y) > len(b) { // ERROR "Disproved Greater64$"
487                 return
488         }
489 }
490
491 func f19() (e int64, err error) {
492         // Issue 29502: slice[:0] is incorrectly disproved.
493         var stack []int64
494         stack = append(stack, 123)
495         if len(stack) > 1 {
496                 panic("too many elements")
497         }
498         last := len(stack) - 1
499         e = stack[last]
500         // Buggy compiler prints "Disproved Geq64" for the next line.
501         stack = stack[:last] // ERROR "Proved IsSliceInBounds"
502         return e, nil
503 }
504
505 func sm1(b []int, x int) {
506         // Test constant argument to slicemask.
507         useSlice(b[2:8]) // ERROR "Proved slicemask not needed$"
508         // Test non-constant argument with known limits.
509         if cap(b) > 10 {
510                 useSlice(b[2:]) // ERROR "Proved slicemask not needed$"
511         }
512 }
513
514 func lim1(x, y, z int) {
515         // Test relations between signed and unsigned limits.
516         if x > 5 {
517                 if uint(x) > 5 { // ERROR "Proved Greater64U$"
518                         return
519                 }
520         }
521         if y >= 0 && y < 4 {
522                 if uint(y) > 4 { // ERROR "Disproved Greater64U$"
523                         return
524                 }
525                 if uint(y) < 5 { // ERROR "Proved Less64U$"
526                         return
527                 }
528         }
529         if z < 4 {
530                 if uint(z) > 4 { // Not provable without disjunctions.
531                         return
532                 }
533         }
534 }
535
536 // fence1–4 correspond to the four fence-post implications.
537
538 func fence1(b []int, x, y int) {
539         // Test proofs that rely on fence-post implications.
540         if x+1 > y {
541                 if x < y { // ERROR "Disproved Less64$"
542                         return
543                 }
544         }
545         if len(b) < cap(b) {
546                 // This eliminates the growslice path.
547                 b = append(b, 1) // ERROR "Disproved Greater64U$"
548         }
549 }
550
551 func fence2(x, y int) {
552         if x-1 < y {
553                 if x > y { // ERROR "Disproved Greater64$"
554                         return
555                 }
556         }
557 }
558
559 func fence3(b, c []int, x, y int64) {
560         if x-1 >= y {
561                 if x <= y { // Can't prove because x may have wrapped.
562                         return
563                 }
564         }
565
566         if x != math.MinInt64 && x-1 >= y {
567                 if x <= y { // ERROR "Disproved Leq64$"
568                         return
569                 }
570         }
571
572         c[len(c)-1] = 0 // Can't prove because len(c) might be 0
573
574         if n := len(b); n > 0 {
575                 b[n-1] = 0 // ERROR "Proved IsInBounds$"
576         }
577 }
578
579 func fence4(x, y int64) {
580         if x >= y+1 {
581                 if x <= y {
582                         return
583                 }
584         }
585         if y != math.MaxInt64 && x >= y+1 {
586                 if x <= y { // ERROR "Disproved Leq64$"
587                         return
588                 }
589         }
590 }
591
592 // Check transitive relations
593 func trans1(x, y int64) {
594         if x > 5 {
595                 if y > x {
596                         if y > 2 { // ERROR "Proved Greater64$"
597                                 return
598                         }
599                 } else if y == x {
600                         if y > 5 { // ERROR "Proved Greater64$"
601                                 return
602                         }
603                 }
604         }
605         if x >= 10 {
606                 if y > x {
607                         if y > 10 { // ERROR "Proved Greater64$"
608                                 return
609                         }
610                 }
611         }
612 }
613
614 func trans2(a, b []int, i int) {
615         if len(a) != len(b) {
616                 return
617         }
618
619         _ = a[i]
620         _ = b[i] // ERROR "Proved IsInBounds$"
621 }
622
623 func trans3(a, b []int, i int) {
624         if len(a) > len(b) {
625                 return
626         }
627
628         _ = a[i]
629         _ = b[i] // ERROR "Proved IsInBounds$"
630 }
631
632 // Derived from nat.cmp
633 func natcmp(x, y []uint) (r int) {
634         m := len(x)
635         n := len(y)
636         if m != n || m == 0 {
637                 return
638         }
639
640         i := m - 1
641         for i > 0 && // ERROR "Induction variable: limits \(0,\?\], increment 1$"
642                 x[i] == // ERROR "Proved IsInBounds$"
643                         y[i] { // ERROR "Proved IsInBounds$"
644                 i--
645         }
646
647         switch {
648         case x[i] < // todo, cannot prove this because it's dominated by i<=0 || x[i]==y[i]
649                 y[i]: // ERROR "Proved IsInBounds$"
650                 r = -1
651         case x[i] > // ERROR "Proved IsInBounds$"
652                 y[i]: // ERROR "Proved IsInBounds$"
653                 r = 1
654         }
655         return
656 }
657
658 func suffix(s, suffix string) bool {
659         // todo, we're still not able to drop the bound check here in the general case
660         return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
661 }
662
663 func constsuffix(s string) bool {
664         return suffix(s, "abc") // ERROR "Proved IsSliceInBounds$"
665 }
666
667 // oforuntil tests the pattern created by OFORUNTIL blocks. These are
668 // handled by addLocalInductiveFacts rather than findIndVar.
669 func oforuntil(b []int) {
670         i := 0
671         if len(b) > i {
672         top:
673                 println(b[i]) // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Proved IsInBounds$"
674                 i++
675                 if i < len(b) {
676                         goto top
677                 }
678         }
679 }
680
681 // The range tests below test the index variable of range loops.
682
683 // range1 compiles to the "efficiently indexable" form of a range loop.
684 func range1(b []int) {
685         for i, v := range b { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
686                 b[i] = v + 1    // ERROR "Proved IsInBounds$"
687                 if i < len(b) { // ERROR "Proved Less64$"
688                         println("x")
689                 }
690                 if i >= 0 { // ERROR "Proved Geq64$"
691                         println("x")
692                 }
693         }
694 }
695
696 // range2 elements are larger, so they use the general form of a range loop.
697 func range2(b [][32]int) {
698         for i, v := range b {
699                 b[i][0] = v[0] + 1 // ERROR "Induction variable: limits \[0,\?\), increment 1$" "Proved IsInBounds$"
700                 if i < len(b) {    // ERROR "Proved Less64$"
701                         println("x")
702                 }
703                 if i >= 0 { // ERROR "Proved Geq64$"
704                         println("x")
705                 }
706         }
707 }
708
709 //go:noinline
710 func useInt(a int) {
711 }
712
713 //go:noinline
714 func useSlice(a []int) {
715 }
716
717 func main() {
718 }