[WinEH] Disallow cyclic unwinds
[oota-llvm.git] / test / Verifier / invalid-eh.ll
1 ; RUN: sed -e s/.T1:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s
2 ; RUN: sed -e s/.T2:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s
3 ; RUN: sed -e s/.T3:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %s
4 ; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s
5 ; RUN: sed -e s/.T5:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK5 %s
6 ; RUN: sed -e s/.T6:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s
7 ; RUN: sed -e s/.T7:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK7 %s
8 ; RUN: sed -e s/.T8:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK8 %s
9 ; RUN: sed -e s/.T9:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK9 %s
10 ; RUN: sed -e s/.T10:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK10 %s
11 ; RUN: sed -e s/.T11:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK11 %s
12 ; RUN: sed -e s/.T12:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK12 %s
13 ; RUN: sed -e s/.T13:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK13 %s
14 ; RUN: sed -e s/.T14:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK14 %s
15 ; RUN: sed -e s/.T15:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK15 %s
16 ; RUN: sed -e s/.T16:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK16 %s
17 ; RUN: sed -e s/.T17:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK17 %s
18 ; RUN: sed -e s/.T18:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK18 %s
19 ; RUN: sed -e s/.T19:// %s | not opt -verify -disable-output 2>&1 | FileCheck --check-prefix=CHECK19 %s
20
21 declare void @g()
22
23 ;T1: define void @f() {
24 ;T1:   entry:
25 ;T1:     catchret from undef to label %next
26 ;T1:     ; CHECK1: CatchReturnInst needs to be provided a CatchPad
27 ;T1:   next:
28 ;T1:     unreachable
29 ;T1: }
30
31 ;T2: define void @f() {
32 ;T2:   entry:
33 ;T2:     %x = cleanuppad within none []
34 ;T2:     ; catchret's first operand's operator must be catchpad
35 ;T2:     catchret from %x to label %entry
36 ;T2:     ; CHECK2: CatchReturnInst needs to be provided a CatchPad
37 ;T2: }
38
39 ;T3: define void @f() {
40 ;T3:   entry:
41 ;T3:     cleanupret from undef unwind label %next
42 ;T3:     ; CHECK3: CleanupReturnInst needs to be provided a CleanupPad
43 ;T3:   next:
44 ;T3:     unreachable
45 ;T3: }
46
47 ;T4: define void @f() {
48 ;T4:   entry:
49 ;T4:     %cs = catchswitch within none [label %next] unwind to caller
50 ;T4:   next:
51 ;T4:     %x = catchpad within %cs []
52 ;T4:     ; cleanupret first operand's operator must be cleanuppad
53 ;T4:     cleanupret from %x unwind to caller
54 ;T4:     ; CHECK4: CleanupReturnInst needs to be provided a CleanupPad
55 ;T4: }
56
57 ;T5: define void @f() personality void ()* @g {
58 ;T5:   entry:
59 ;T5:     ret void
60 ;T5:   switch:
61 ;T5:     %cs = catchswitch within none [label %catch] unwind to caller
62 ;T5:   catch:
63 ;T5:     catchpad within %cs []
64 ;T5:     unreachable
65 ;T5:   bogus:
66 ;T5:     cleanuppad within %cs []
67 ;T5:     ; CHECK5: CleanupPadInst has an invalid parent
68 ;T5:     unreachable
69 ;T5: }
70
71 ;T6: define void @f() personality void ()* @g {
72 ;T6:   entry:
73 ;T6:     ret void
74 ;T6:   switch1:
75 ;T6:     %cs1 = catchswitch within none [label %catch1] unwind label %catch2
76 ;T6:     ; CHECK6: Block containg CatchPadInst must be jumped to only by its catchswitch
77 ;T6:   catch1:
78 ;T6:     catchpad within %cs1 []
79 ;T6:     unreachable
80 ;T6:   switch2:
81 ;T6:     %cs2 = catchswitch within none [label %catch2] unwind to caller
82 ;T6:   catch2:
83 ;T6:     catchpad within %cs2 []
84 ;T6:     unreachable
85 ;T6: }
86
87 ;T7: define void @f() personality void ()* @g {
88 ;T7:   entry:
89 ;T7:     ret void
90 ;T7:   switch1:
91 ;T7:     %cs1 = catchswitch within none [label %catch1] unwind to caller
92 ;T7:   catch1:
93 ;T7:     catchpad within %cs1 []
94 ;T7:     unreachable
95 ;T7:   switch2:
96 ;T7:     %cs2 = catchswitch within %cs1 [label %catch2] unwind to caller
97 ;T7:     ; CHECK7: CatchSwitchInst has an invalid parent
98 ;T7:   catch2:
99 ;T7:     catchpad within %cs2 []
100 ;T7:     unreachable
101 ;T7: }
102
103 ;T8: define void @f() personality void ()* @g {
104 ;T8:   entry:
105 ;T8:     ret void
106 ;T8:   switch1:
107 ;T8:     %cs1 = catchswitch within none [ label %switch1 ] unwind to caller
108 ;T8:     ; CHECK8: CatchSwitchInst handlers must be catchpads
109 ;T8: }
110
111 ;T9: define void @f() personality void ()* @g {
112 ;T9:   entry:
113 ;T9:     ret void
114 ;T9:   cleanup:
115 ;T9:     %cp = cleanuppad within none []
116 ;T9:     invoke void @g() [ "funclet"(token %cp) ]
117 ;T9:       to label %exit unwind label %cleanup
118 ;T9:       ; CHECK9: EH pad cannot handle exceptions raised within it
119 ;T9:       ; CHECK9-NEXT: %cp = cleanuppad within none []
120 ;T9:       ; CHECK9-NEXT: invoke void @g() [ "funclet"(token %cp) ]
121 ;T9:   exit:
122 ;T9:     ret void
123 ;T9: }
124
125 ;T10: define void @f() personality void ()* @g {
126 ;T10:   entry:
127 ;T10:     ret void
128 ;T10:   cleanup1:
129 ;T10:     %cp1 = cleanuppad within none []
130 ;T10:     unreachable
131 ;T10:   switch:
132 ;T10:     %cs = catchswitch within %cp1 [label %catch] unwind to caller
133 ;T10:   catch:
134 ;T10:     %catchp1 = catchpad within %cs [i32 1]
135 ;T10:     unreachable
136 ;T10:   cleanup2:
137 ;T10:     %cp2 = cleanuppad within %catchp1 []
138 ;T10:     unreachable
139 ;T10:   cleanup3:
140 ;T10:     %cp3 = cleanuppad within %cp2 []
141 ;T10:     cleanupret from %cp3 unwind label %switch
142 ;T10:       ; CHECK10: EH pad cannot handle exceptions raised within it
143 ;T10:       ; CHECK10-NEXT: %cs = catchswitch within %cp1 [label %catch] unwind to caller
144 ;T10:       ; CHECK10-NEXT: cleanupret from %cp3 unwind label %switch
145 ;T10: }
146
147 ;T11: define void @f() personality void ()* @g {
148 ;T11:   entry:
149 ;T11:     ret void
150 ;T11:   cleanup1:
151 ;T11:     %cp1 = cleanuppad within none []
152 ;T11:     unreachable
153 ;T11:   cleanup2:
154 ;T11:     %cp2 = cleanuppad within %cp1 []
155 ;T11:     unreachable
156 ;T11:   switch:
157 ;T11:     %cs = catchswitch within none [label %catch] unwind label %cleanup2
158 ;T11:     ; CHECK11: A single unwind edge may only enter one EH pad
159 ;T11:     ; CHECK11-NEXT: %cs = catchswitch within none [label %catch] unwind label %cleanup2
160 ;T11:   catch:
161 ;T11:     catchpad within %cs [i32 1]
162 ;T11:     unreachable
163 ;T11: }
164
165 ;T12: define void @f() personality void ()* @g {
166 ;T12:   entry:
167 ;T12:     ret void
168 ;T12:   cleanup:
169 ;T12:     %cp = cleanuppad within none []
170 ;T12:     cleanupret from %cp unwind label %switch
171 ;T12:     ; CHECK12: A cleanupret must exit its cleanup
172 ;T12:     ; CHECK12-NEXT: cleanupret from %cp unwind label %switch
173 ;T12:   switch:
174 ;T12:     %cs = catchswitch within %cp [label %catch] unwind to caller
175 ;T12:   catch:
176 ;T12:     catchpad within %cs [i32 1]
177 ;T12:     unreachable
178 ;T12: }
179
180 ;T13: define void @f() personality void ()* @g {
181 ;T13:   entry:
182 ;T13:     ret void
183 ;T13:   switch:
184 ;T13:     %cs = catchswitch within none [label %catch] unwind label %switch
185 ;T13:     ; CHECK13: EH pad cannot handle exceptions raised within it
186 ;T13:     ; CHECK13-NEXT:  %cs = catchswitch within none [label %catch] unwind label %switch
187 ;T13:   catch:
188 ;T13:     catchpad within %cs [i32 0]
189 ;T13:     unreachable
190 ;T13: }
191
192 ;T14: define void @f() personality void ()* @g {
193 ;T14:   entry:
194 ;T14:     ret void
195 ;T14:   cleanup:
196 ;T14:     %cp = cleanuppad within none []
197 ;T14:     unreachable
198 ;T14:   left:
199 ;T14:     cleanupret from %cp unwind label %switch
200 ;T14:   right:
201 ;T14:     cleanupret from %cp unwind to caller
202 ;T14:     ; CHECK14: Unwind edges out of a funclet pad must have the same unwind dest
203 ;T14:     ; CHECK14-NEXT: %cp = cleanuppad within none []
204 ;T14:     ; CHECK14-NEXT: cleanupret from %cp unwind label %switch
205 ;T14:     ; CHECK14-NEXT: cleanupret from %cp unwind to caller
206 ;T14:   switch:
207 ;T14:     %cs = catchswitch within none [label %catch] unwind to caller
208 ;T14:   catch:
209 ;T14:     catchpad within %cs [i32 1]
210 ;T14:     unreachable
211 ;T14: }
212
213 ;T15: define void @f() personality void ()* @g {
214 ;T15:   entry:
215 ;T15:     ret void
216 ;T15:   switch:
217 ;T15:     %cs = catchswitch within none [label %catch] unwind to caller
218 ;T15:   catch:
219 ;T15:     %catch.pad = catchpad within %cs [i32 1]
220 ;T15:     invoke void @g() [ "funclet"(token %catch.pad) ]
221 ;T15:       to label %unreachable unwind label %target1
222 ;T15:   unreachable:
223 ;T15:     unreachable
224 ;T15:   target1:
225 ;T15:     cleanuppad within none []
226 ;T15:     unreachable
227 ;T15:   target2:
228 ;T15:     cleanuppad within none []
229 ;T15:     unreachable
230 ;T15:   nested.1:
231 ;T15:     %nested.pad.1 = cleanuppad within %catch.pad []
232 ;T15:     unreachable
233 ;T15:   nested.2:
234 ;T15:     %nested.pad.2 = cleanuppad within %nested.pad.1 []
235 ;T15:     cleanupret from %nested.pad.2 unwind label %target2
236 ;T15:     ; CHECK15: Unwind edges out of a funclet pad must have the same unwind dest
237 ;T15:     ; CHECK15-NEXT: %catch.pad = catchpad within %cs [i32 1]
238 ;T15:     ; CHECK15-NEXT: cleanupret from %nested.pad.2 unwind label %target2
239 ;T15:     ; CHECK15-NEXT: invoke void @g() [ "funclet"(token %catch.pad) ]
240 ;T15:     ; CHECK15-NEXT:   to label %unreachable unwind label %target1
241 ;T15: }
242
243 ;T16: define void @f() personality void ()* @g {
244 ;T16:   entry:
245 ;T16:     ret void
246 ;T16:   switch:
247 ;T16:     %cs = catchswitch within none [label %catch] unwind to caller
248 ;T16:   catch:
249 ;T16:     %catch.pad = catchpad within %cs [i32 1]
250 ;T16:     invoke void @g() [ "funclet"(token %catch.pad) ]
251 ;T16:       to label %unreachable unwind label %target1
252 ;T16:     ; CHECK16: Unwind edges out of a catch must have the same unwind dest as the parent catchswitch
253 ;T16:     ; CHECK16-NEXT:   %catch.pad = catchpad within %cs [i32 1]
254 ;T16:     ; CHECK16-NEXT:  invoke void @g() [ "funclet"(token %catch.pad) ]
255 ;T16:     ; CHECK16-NEXT:          to label %unreachable unwind label %target1
256 ;T16:     ; CHECK16-NEXT:  %cs = catchswitch within none [label %catch] unwind to caller
257 ;T16:   unreachable:
258 ;T16:     unreachable
259 ;T16:   target1:
260 ;T16:     cleanuppad within none []
261 ;T16:     unreachable
262 ;T16: }
263
264 ;T17: define void @f() personality void ()* @g {
265 ;T17:   entry:
266 ;T17:     ret void
267 ;T17:   switch:
268 ;T17:     %cs = catchswitch within none [label %catch] unwind label %target1
269 ;T17:   catch:
270 ;T17:     %catch.pad = catchpad within %cs [i32 1]
271 ;T17:     invoke void @g() [ "funclet"(token %catch.pad) ]
272 ;T17:       to label %unreachable unwind label %target2
273 ;T17:     ; CHECK17: Unwind edges out of a catch must have the same unwind dest as the parent catchswitch
274 ;T17:     ; CHECK17-NEXT:  %catch.pad = catchpad within %cs [i32 1]
275 ;T17:     ; CHECK17-NEXT:  invoke void @g() [ "funclet"(token %catch.pad) ]
276 ;T17:     ; CHECK17-NEXT:          to label %unreachable unwind label %target2
277 ;T17:     ; CHECK17-NEXT:  %cs = catchswitch within none [label %catch] unwind label %target1
278 ;T17:   unreachable:
279 ;T17:     unreachable
280 ;T17:   target1:
281 ;T17:     cleanuppad within none []
282 ;T17:     unreachable
283 ;T17:   target2:
284 ;T17:     cleanuppad within none []
285 ;T17:     unreachable
286 ;T17: }
287
288 ;T18: define void @f() personality void ()* @g {
289 ;T18:   entry:
290 ;T18:     invoke void @g()
291 ;T18:       to label %invoke.cont unwind label %left
292 ;T18:   invoke.cont:
293 ;T18:     invoke void @g()
294 ;T18:       to label %unreachable unwind label %right
295 ;T18:   left:
296 ;T18:     %cp.left = cleanuppad within none []
297 ;T18:     invoke void @g() [ "funclet"(token %cp.left) ]
298 ;T18:       to label %unreachable unwind label %right
299 ;T18:   right:
300 ;T18:     %cp.right = cleanuppad within none []
301 ;T18:     invoke void @g() [ "funclet"(token %cp.right) ]
302 ;T18:       to label %unreachable unwind label %left
303 ;T18:     ; CHECK18: EH pads can't handle each other's exceptions
304 ;T18:     ; CHECK18-NEXT: %cp.left = cleanuppad within none []
305 ;T18:     ; CHECK18-NEXT:  invoke void @g() [ "funclet"(token %cp.left) ]
306 ;T18:     ; CHECK18-NEXT:          to label %unreachable unwind label %right
307 ;T18:     ; CHECK18-NEXT:  %cp.right = cleanuppad within none []
308 ;T18:     ; CHECK18-NEXT:  invoke void @g() [ "funclet"(token %cp.right) ]
309 ;T18:     ; CHECK18-NEXT:          to label %unreachable unwind label %left
310 ;T18:   unreachable:
311 ;T18:     unreachable
312 ;T18: }
313
314 ;T19: define void @f() personality void ()* @g {
315 ;T19:   entry:
316 ;T19:     ret void
317 ;T19:   red:
318 ;T19:     %redpad = cleanuppad within none []
319 ;T19:     unreachable
320 ;T19:   red.inner:
321 ;T19:     %innerpad = cleanuppad within %redpad []
322 ;T19:     invoke void @g() [ "funclet"(token %innerpad) ]
323 ;T19:       to label %unreachable unwind label %green
324 ;T19:   green:
325 ;T19:     %greenswitch = catchswitch within none [label %catch] unwind label %blue
326 ;T19:   catch:
327 ;T19:     catchpad within %greenswitch [i32 42]
328 ;T19:     unreachable
329 ;T19:   blue:
330 ;T19:     %bluepad = cleanuppad within none []
331 ;T19:     cleanupret from %bluepad unwind label %red
332 ;T19:     ; CHECK19: EH pads can't handle each other's exceptions
333 ;T19:     ; CHECK19-NEXT: %redpad = cleanuppad within none []
334 ;T19:     ; CHECK19-NEXT: invoke void @g() [ "funclet"(token %innerpad) ]
335 ;T19:     ; CHECK19-NEXT:         to label %unreachable unwind label %green
336 ;T19:     ; CHECK19-NEXT: %greenswitch = catchswitch within none [label %catch] unwind label %blue
337 ;T19:     ; CHECK19-NEXT: %bluepad = cleanuppad within none []
338 ;T19:     ; CHECK19-NEXT: cleanupret from %bluepad unwind label %red
339 ;T19:   unreachable:
340 ;T19:     unreachable
341 ;T19: }