]> Cypherpunks.ru repositories - gostls13.git/blob - test/index.go
test: fix index.go to pass with recent index checks
[gostls13.git] / test / index.go
1 // $G $D/$F.go && $L $F.$A &&
2 // ./$A.out -pass 0 >tmp.go && $G tmp.go && $L -o $A.out1 tmp.$A && ./$A.out1 &&
3 // ./$A.out -pass 1 >tmp.go && errchk $G -e tmp.go &&
4 // ./$A.out -pass 2 >tmp.go && errchk $G -e tmp.go
5 // rm -f tmp.go $A.out1
6
7 // NOTE: This test is not run by 'run.go' and so not run by all.bash.
8 // To run this test you must use the ./run shell script.
9
10 // Copyright 2010 The Go Authors.  All rights reserved.
11 // Use of this source code is governed by a BSD-style
12 // license that can be found in the LICENSE file.
13
14 // Generate test of index and slice bounds checks.
15 // The output is compiled and run.
16
17 package main
18
19 import (
20         "bufio"
21         "flag"
22         "fmt"
23         "os"
24         "runtime"
25 )
26
27 const prolog = `
28
29 package main
30
31 import (
32         "runtime"
33 )
34
35 type quad struct { x, y, z, w int }
36
37 const (
38         cj = 100011
39         ci int = 100012
40         ci8 int8 = 115
41         ci16 int16 = 10016
42         ci32 int32 = 100013
43         ci64 int64 = 100014
44         ci64big int64 = 1<<31
45         ci64bigger int64 = 1<<32
46         chuge = 1<<100
47
48         cnj = -2
49         cni int = -3
50         cni8 int8 = -6
51         cni16 int16 = -7
52         cni32 int32 = -4
53         cni64 int64 = -5
54         cni64big int64 = -1<<31
55         cni64bigger int64 = -1<<32
56         cnhuge = -1<<100
57 )
58
59 var j int = 100020
60 var i int = 100021
61 var i8 int8 = 126
62 var i16 int16 = 10025
63 var i32 int32 = 100022
64 var i64 int64 = 100023
65 var i64big int64 = 1<<31
66 var i64bigger int64 = 1<<32
67 var huge uint64 = 1<<64 - 1
68
69 var nj int = -10
70 var ni int = -11
71 var ni8 int8 = -14
72 var ni16 int16 = -15
73 var ni32 int32 = -12
74 var ni64 int64 = -13
75 var ni64big int64 = -1<<31
76 var ni64bigger int64 = -1<<32
77 var nhuge int64 = -1<<63
78
79 var si []int = make([]int, 10)
80 var ai [10]int
81 var pai *[10]int = &ai
82
83 var sq []quad = make([]quad, 10)
84 var aq [10]quad
85 var paq *[10]quad = &aq
86
87 var sib []int = make([]int, 100000)
88 var aib [100000]int
89 var paib *[100000]int = &aib
90
91 var sqb []quad = make([]quad, 100000)
92 var aqb [100000]quad
93 var paqb *[100000]quad = &aqb
94
95 type T struct {
96         si []int
97         ai [10]int
98         pai *[10]int
99         sq []quad
100         aq [10]quad
101         paq *[10]quad
102
103         sib []int
104         aib [100000]int
105         paib *[100000]int
106         sqb []quad
107         aqb [100000]quad
108         paqb *[100000]quad
109 }
110
111 var t = T{si, ai, pai, sq, aq, paq, sib, aib, paib, sqb, aqb, paqb}
112
113 var pt = &T{si, ai, pai, sq, aq, paq, sib, aib, paib, sqb, aqb, paqb}
114
115 // test that f panics
116 func test(f func(), s string) {
117         defer func() {
118                 if err := recover(); err == nil {
119                         _, file, line, _ := runtime.Caller(2)
120                         bug()
121                         print(file, ":", line, ": ", s, " did not panic\n")
122                 } else if !contains(err.(error).Error(), "out of range") {
123                         _, file, line, _ := runtime.Caller(2)
124                         bug()
125                         print(file, ":", line, ": ", s, " unexpected panic: ", err.(error).Error(), "\n")
126                 }
127         }()
128         f()
129 }
130
131 func contains(x, y string) bool {
132         for i := 0; i+len(y) <= len(x); i++ {
133                 if x[i:i+len(y)] == y {
134                         return true
135                 }
136         }
137         return false
138 }
139
140
141 var X interface{}
142 func use(y interface{}) {
143         X = y
144 }
145
146 var didBug = false
147
148 func bug() {
149         if !didBug {
150                 didBug = true
151                 println("BUG")
152         }
153 }
154
155 func main() {
156 `
157
158 // Passes:
159 //      0 - dynamic checks
160 //      1 - static checks of invalid constants (cannot assign to types)
161 //      2 - static checks of array bounds
162 var pass = flag.Int("pass", 0, "which test (0,1,2)")
163
164 func testExpr(b *bufio.Writer, expr string) {
165         if *pass == 0 {
166                 fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\n", expr, expr)
167         } else {
168                 fmt.Fprintf(b, "\tuse(%s)  // ERROR \"index|overflow\"\n", expr)
169         }
170 }
171
172 func main() {
173         b := bufio.NewWriter(os.Stdout)
174
175         flag.Parse()
176         
177         if *pass == 0 {
178                 fmt.Fprint(b, "// $G $D/$F.go && $L $F.$A && ./$A.out\n\n")
179         } else {
180                 fmt.Fprint(b, "// errchk $G -e $D/$F.go\n\n")
181         }
182         fmt.Fprint(b, prolog)
183         
184         var choices = [][]string{
185                 // Direct value, fetch from struct, fetch from struct pointer.
186                 // The last two cases get us to oindex_const_sudo in gsubr.c.
187                 []string{"", "t.", "pt."},
188                 
189                 // Array, pointer to array, slice.
190                 []string{"a", "pa", "s"},
191                 
192                 // Element is int, element is quad (struct).
193                 // This controls whether we end up in gsubr.c (i) or cgen.c (q).
194                 []string{"i", "q"},
195
196                 // Small or big len.
197                 []string{"", "b"},
198
199                 // Variable or constant.
200                 []string{"", "c"},
201
202                 // Positive or negative.
203                 []string{"", "n"},
204
205                 // Size of index.
206                 []string{"j", "i", "i8", "i16", "i32", "i64", "i64big", "i64bigger", "huge"},
207         }
208         
209         forall(choices, func(x []string) {
210                 p, a, e, big, c, n, i := x[0], x[1], x[2], x[3], x[4], x[5], x[6]
211
212                 // Pass: dynamic=0, static=1, 2.
213                 // Which cases should be caught statically?
214                 // Only constants, obviously.
215                 // Beyond that, must be one of these:
216                 //      indexing into array or pointer to array
217                 //      negative constant
218                 //      large constant
219                 thisPass := 0
220                 if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge") {
221                         if i == "huge" {
222                                 // Due to a detail of 6g's internals,
223                                 // the huge constant errors happen in an
224                                 // earlier pass than the others and inhibits
225                                 // the next pass from running.
226                                 // So run it as a separate check.
227                                 thisPass = 1
228                         } else if a == "s" && n == "" && (i == "i64big" || i == "i64bigger") && runtime.GOARCH == "amd64" {
229                                 // On amd64, these huge numbers do fit in an int, so they are not
230                                 // rejected at compile time.
231                                 thisPass = 0
232                         } else {
233                                 thisPass = 2
234                         }
235                 }
236                 
237                 // If we're using the big-len data, positive int8 and int16 cannot overflow.
238                 if big == "b" && n == "" && (i == "i8" || i == "i16") {
239                         return
240                 }
241
242                 // Only print the test case if it is appropriate for this pass.
243                 if thisPass == *pass {
244                         pae := p+a+e+big
245                         cni := c+n+i
246                         
247                         // Index operation
248                         testExpr(b, pae + "[" + cni + "]")
249                         
250                         // Slice operation.
251                         // Low index 0 is a special case in ggen.c
252                         // so test both 0 and 1.
253                         testExpr(b, pae + "[0:" + cni + "]")
254                         testExpr(b, pae + "[1:" + cni + "]")
255                         testExpr(b, pae + "[" + cni + ":]")
256                         testExpr(b, pae + "[" + cni + ":" + cni + "]")
257                 }
258         })
259
260         fmt.Fprintln(b, "}")
261         b.Flush()
262 }
263
264 func forall(choices [][]string, f func([]string)) {
265         x := make([]string, len(choices))
266         
267         var recurse func(d int)
268         recurse = func(d int) {
269                 if d >= len(choices) {
270                         f(x)
271                         return
272                 }
273                 for _, x[d] = range choices[d] {
274                         recurse(d+1)
275                 }
276         }
277         recurse(0)
278 }