1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(trycatch_SUITE).
21
22-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
23	 init_per_group/2,end_per_group/2,basic/1,lean_throw/1,
24	 try_of/1,try_after/1,%after_bind/1,
25	 catch_oops/1,after_oops/1,eclectic/1,rethrow/1,
26	 nested_of/1,nested_catch/1,nested_after/1,
27	 nested_horrid/1,last_call_optimization/1,bool/1,
28	 plain_catch_coverage/1,andalso_orelse/1,get_in_try/1,
29	 hockey/1,handle_info/1,catch_in_catch/1,grab_bag/1,
30         stacktrace/1,nested_stacktrace/1,raise/1,
31         no_return_in_try_block/1,
32         expression_export/1,
33         throw_opt_crash/1,
34         coverage/1]).
35
36-include_lib("common_test/include/ct.hrl").
37
38suite() -> [{ct_hooks,[ts_install_cth]}].
39
40all() ->
41    [{group,p}].
42
43groups() ->
44    [{p,[parallel],
45      [basic,lean_throw,try_of,try_after,catch_oops,
46       after_oops,eclectic,rethrow,nested_of,nested_catch,
47       nested_after,nested_horrid,last_call_optimization,
48       bool,plain_catch_coverage,andalso_orelse,get_in_try,
49       hockey,handle_info,catch_in_catch,grab_bag,
50       stacktrace,nested_stacktrace,raise,
51       no_return_in_try_block,expression_export,
52       throw_opt_crash,
53       coverage]}].
54
55
56init_per_suite(Config) ->
57    test_lib:recompile(?MODULE),
58    Config.
59
60end_per_suite(_Config) ->
61    ok.
62
63init_per_group(_GroupName, Config) ->
64    Config.
65
66end_per_group(_GroupName, Config) ->
67    Config.
68
69
70
71basic(Conf) when is_list(Conf) ->
72    2 =
73	try my_div(4, 2)
74	catch
75            Class:Reason -> {Class,Reason}
76	end,
77    error =
78        try my_div(1, 0)
79        catch
80            error:badarith -> error
81        end,
82    error =
83        try 1.0 / zero()
84        catch
85            error:badarith -> error
86        end,
87    ok =
88        try my_add(53, atom)
89        catch
90            error:badarith -> ok
91        end,
92    exit_nisse =
93        try exit(nisse)
94	catch
95            exit:nisse -> exit_nisse
96        end,
97    ok =
98        try throw(kalle)
99        catch
100            kalle -> ok
101        end,
102
103    %% Try some stuff where the compiler will optimize away the try.
104
105    V = id({a,variable}),
106    V = try V catch nisse -> error end,
107    42 = try 42 catch nisse -> error end,
108    [V] = try [V] catch nisse -> error end,
109    {ok,V} = try {ok,V} catch nisse -> error end,
110
111    %% Same idea, but use an after too.
112
113    V = try V catch nisse -> error after after_call() end,
114    after_clean(),
115    42 = try 42 after after_call() end,
116    after_clean(),
117    [V] = try [V] catch nisse -> error after after_call() end,
118    after_clean(),
119    {ok,V} = try {ok,V} after after_call() end,
120
121    %% Try/of
122    ok = try V of
123	     {a,variable} -> ok
124	 catch nisse -> erro
125	 end,
126
127    %% Unmatchable clauses.
128    try
129        throw(thrown)
130    catch
131        {a,b}={a,b,c} ->                        %Intentionally no match.
132            ok;
133        thrown ->
134            ok
135    end,
136
137    ok.
138
139after_call() ->
140    put(basic, after_was_called).
141
142after_clean() ->
143    after_was_called = erase(basic).
144
145
146lean_throw(Conf) when is_list(Conf) ->
147    {throw,kalle} =
148        try throw(kalle)
149        catch
150            Kalle -> {throw,Kalle}
151        end,
152    {exit,kalle} =
153        try exit(kalle)
154        catch
155            Throw1 -> {throw,Throw1};
156	    exit:Reason1 -> {exit,Reason1}
157        end,
158    {exit,kalle} =
159        try exit(kalle)
160        catch
161	    exit:Reason2 -> {exit,Reason2};
162            Throw2 -> {throw,Throw2}
163        end,
164    {exit,kalle} =
165        try try exit(kalle)
166            catch
167                Throw3 -> {throw,Throw3}
168            end
169        catch
170            exit:Reason3 -> {exit,Reason3}
171        end,
172    ok.
173
174
175
176try_of(Conf) when is_list(Conf) ->
177    {ok,{some,content}} =
178	try_of_1({value,{good,{some,content}}}),
179    {error,[other,content]} =
180	try_of_1({value,{bad,[other,content]}}),
181    {caught,{exit,{ex,it,[reason]}}} =
182	try_of_1({exit,{ex,it,[reason]}}),
183    {caught,{throw,[term,{in,a,{tuple}}]}} =
184	try_of_1({throw,[term,{in,a,{tuple}}]}),
185    {caught,{error,[bad,arg]}} =
186	try_of_1({error,[bad,arg]}),
187    {caught,{error,badarith}} =
188	try_of_1({'div',{1,0}}),
189    {caught,{error,badarith}} =
190	try_of_1({'add',{a,0}}),
191    {caught,{error,badarg}} =
192	try_of_1({'abs',x}),
193    {caught,{error,function_clause}} =
194	try_of_1(illegal),
195    {error,{try_clause,{some,other_garbage}}} =
196	try try_of_1({value,{some,other_garbage}})
197        catch error:Reason -> {error,Reason}
198        end,
199    ok.
200
201try_of_1(X) ->
202    try foo(X) of
203        {good,Y} -> {ok,Y};
204	{bad,Y} -> {error,Y}
205    catch
206	Class:Reason ->
207             {caught,{Class,Reason}}
208    end.
209
210try_after(Conf) when is_list(Conf) ->
211    try_after_1(fun try_after_basic/2),
212    try_after_1(fun try_after_catch/2),
213    try_after_1(fun try_after_complex/2),
214    try_after_1(fun try_after_fun/2),
215    try_after_1(fun try_after_letrec/2),
216    try_after_1(fun try_after_protect/2),
217    try_after_1(fun try_after_receive/2),
218    try_after_1(fun try_after_receive_timeout/2),
219    try_after_1(fun try_after_try/2),
220    ok.
221
222try_after_1(TestFun) ->
223    {{ok,[some,value],undefined},finalized} =
224        TestFun({value,{ok,[some,value]}},finalized),
225    {{error,badarith,undefined},finalized} =
226        TestFun({'div',{1,0}},finalized),
227    {{error,badarith,undefined},finalized} =
228        TestFun({'add',{1,a}},finalized),
229    {{error,badarg,undefined},finalized} =
230        TestFun({'abs',a},finalized),
231    {{error,[the,{reason}],undefined},finalized} =
232        TestFun({error,[the,{reason}]},finalized),
233    {{throw,{thrown,[reason]},undefined},finalized} =
234        TestFun({throw,{thrown,[reason]}},finalized),
235    {{exit,{exited,{reason}},undefined},finalized} =
236        TestFun({exit,{exited,{reason}}},finalized),
237    {{error,function_clause,undefined},finalized} =
238        TestFun(function_clause,finalized),
239    ok =
240        try
241            TestFun({'add',{1,1}}, finalized)
242        catch
243            error:{try_clause,2} -> ok
244        end,
245    finalized = erase(try_after),
246    ok =
247        try
248            try
249                foo({exit,[reaso,{n}]})
250            after
251                put(try_after, finalized)
252            end
253        catch
254            exit:[reaso,{n}] -> ok
255        end,
256    ok.
257
258-define(TRY_AFTER_TESTCASE(Block),
259    erase(try_after),
260    Try =
261        try foo(X) of
262            {ok,Value} -> {ok,Value,get(try_after)}
263        catch
264            Reason -> {throw,Reason,get(try_after)};
265            error:Reason -> {error,Reason,get(try_after)};
266            exit:Reason ->  {exit,Reason,get(try_after)}
267        after
268            Block,
269            put(try_after, Y)
270        end,
271    {Try,erase(try_after)}).
272
273try_after_basic(X, Y) ->
274    ?TRY_AFTER_TESTCASE(ok).
275
276try_after_catch(X, Y) ->
277    ?TRY_AFTER_TESTCASE((catch put(try_after, Y))).
278
279try_after_complex(X, Y) ->
280    %% Large 'after' block, going above the threshold for wrapper functions.
281    ?TRY_AFTER_TESTCASE(case get(try_after) of
282                            unreachable_0 -> dummy:unreachable_0();
283                            unreachable_1 -> dummy:unreachable_1();
284                            unreachable_2 -> dummy:unreachable_2();
285                            unreachable_3 -> dummy:unreachable_3();
286                            unreachable_4 -> dummy:unreachable_4();
287                            unreachable_5 -> dummy:unreachable_5();
288                            unreachable_6 -> dummy:unreachable_6();
289                            unreachable_7 -> dummy:unreachable_7();
290                            unreachable_8 -> dummy:unreachable_8();
291                            unreachable_9 -> dummy:unreachable_9();
292                            _ -> put(try_after, Y)
293                        end).
294
295try_after_fun(X, Y) ->
296    ?TRY_AFTER_TESTCASE((fun() -> ok end)()).
297
298try_after_letrec(X, Y) ->
299    List = lists:duplicate(100, ok),
300    ?TRY_AFTER_TESTCASE([L || L <- List]).
301
302try_after_protect(X, Y) ->
303    ?TRY_AFTER_TESTCASE(case get(try_after) of
304                            N when element(52, N) < 32 -> ok;
305                            _ -> ok
306                        end).
307
308try_after_receive(X, Y) ->
309    Ref = make_ref(),
310    self() ! Ref,
311    ?TRY_AFTER_TESTCASE(receive
312                            Ref -> Ref
313                        end).
314
315try_after_receive_timeout(X, Y) ->
316    Ref = make_ref(),
317    self() ! Ref,
318    ?TRY_AFTER_TESTCASE(receive
319                            Ref -> Ref
320                        after 1000 -> ok
321                        end).
322
323try_after_try(X, Y) ->
324    ?TRY_AFTER_TESTCASE(try
325                            put(try_after, Y)
326                        catch
327                            _ -> ok
328                        end).
329
330-ifdef(begone).
331
332after_bind(Conf) when is_list(Conf) ->
333    V = [make_ref(),self()|value],
334    {value,{value,V}} =
335	after_bind_1({value,V}, V, {value,V}),
336    ok.
337
338after_bind_1(X, V, Y) ->
339    try
340        Try =
341            try foo(X) of
342                V -> value
343            catch
344                C1:V -> {caught,C1}
345            after
346                After = foo(Y)
347	    end,
348        {Try,After}
349    of
350        V -> {value,V}
351    catch
352        C:D -> {caught,{C,D}}
353    end.
354
355-endif.
356
357
358
359catch_oops(Conf) when is_list(Conf) ->
360    V = {v,[a,l|u],{e},self()},
361    {value,V} = catch_oops_1({value,V}),
362    {value,1} = catch_oops_1({'div',{1,1}}),
363    {error,badarith} = catch_oops_1({'div',{1,0}}),
364    {error,function_clause} = catch_oops_1(function_clause),
365    {throw,V} = catch_oops_1({throw,V}),
366    {exit,V} = catch_oops_1({exit,V}),
367    ok.
368
369catch_oops_1(X) ->
370    Ref = make_ref(),
371    try try foo({error,Ref})
372        catch
373            error:Ref ->
374	        foo(X)
375        end of
376        Value -> {value,Value}
377    catch
378        Class:Data -> {Class,Data}
379    end.
380
381
382
383after_oops(Conf) when is_list(Conf) ->
384    V = {self(),make_ref()},
385
386    {{value,V},V} = after_oops_1({value,V}, {value,V}),
387    {{exit,V},V} = after_oops_1({exit,V}, {value,V}),
388    {{error,V},undefined} = after_oops_1({value,V}, {error,V}),
389    {{error,function_clause},undefined} =
390        after_oops_1({exit,V}, function_clause),
391
392    {{value,V},V} = after_oops_2({value,V}, {value,V}),
393    {{exit,V},V} = after_oops_2({exit,V}, {value,V}),
394    {{error,V},undefined} = after_oops_2({value,V}, {error,V}),
395    {{error,function_clause},undefined} =
396        after_oops_2({exit,V}, function_clause),
397
398    ok.
399
400after_oops_1(X, Y) ->
401    erase(after_oops),
402    Try =
403        try try foo(X)
404            after
405                put(after_oops, foo(Y))
406            end of
407            V -> {value,V}
408        catch
409            C:D -> {C,D}
410        end,
411    {Try,erase(after_oops)}.
412
413after_oops_2(X, Y) ->
414    %% GH-4859: `raw_raise` never got an edge to its catch block, making
415    %% try/catch optimization unsafe.
416    erase(after_oops),
417    Try =
418        try
419            try
420                foo(X)
421            catch E:R:S ->
422                erlang:raise(E, R, S)
423            after
424                put(after_oops, foo(Y))
425            end
426        of
427            V -> {value,V}
428        catch
429            C:D -> {C,D}
430        end,
431    {Try,erase(after_oops)}.
432
433eclectic(Conf) when is_list(Conf) ->
434    V = {make_ref(),3.1415926535,[[]|{}]},
435    {{value,{value,V},V},V} =
436	eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
437    {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
438	eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
439    {{error,{exit,V},{'EXIT',V}},V} =
440	eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
441    {{value,{value,V},V},
442	   {'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}} =
443	eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
444    {{'EXIT',V},V} =
445	eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
446    {{error,{'div',{1,0}},{'EXIT',{badarith,[{erlang,'div',[1,0],_},{?MODULE,my_div,2,_}|_]}}},
447	   {'EXIT',V}} =
448	eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
449    {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
450	   {'EXIT',V}} =
451	eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
452    %%
453    {{value,{value,{value,V},V}},V} =
454	eclectic_2({value,{value,V}}, undefined, {value,V}),
455    {{value,{throw,{value,V},V}},V} =
456	eclectic_2({throw,{value,V}}, throw, {value,V}),
457    {{caught,{'EXIT',V}},undefined} =
458	eclectic_2({value,{value,V}}, undefined, {exit,V}),
459    {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
460	eclectic_2({error,{value,V}}, throw, {error,V}),
461    {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
462	eclectic_2({value,{'abs',V}}, undefined, {value,V}),
463    {{caught,{'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}},V} =
464	eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
465    {{caught,{'EXIT',V}},undefined} =
466	eclectic_2({value,{error,V}}, undefined, {exit,V}),
467    {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
468	eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
469    ok.
470
471eclectic_1(X, C, Y) ->
472    erase(eclectic),
473    Done = make_ref(),
474    Try =
475        try case X of
476		{catch_foo,V} -> catch {Done,foo(V)};
477		{foo,V} -> {Done,foo(V)}
478	    end of
479            {Done,D} -> {value,D,catch foo(D)};
480	    {'EXIT',_}=Exit -> Exit;
481	    D -> {D,catch foo(D)}
482        catch
483            C:D -> {C,D,catch foo(D)}
484        after
485            put(eclectic, catch foo(Y))
486        end,
487    {Try,erase(eclectic)}.
488
489eclectic_2(X, C, Y) ->
490    Done = make_ref(),
491    erase(eclectic),
492    Catch =
493	case
494            catch
495		{Done,
496		 try foo(X) of
497		     V -> {value,V,foo(V)}
498		 catch
499		     C:D -> {C,D,foo(D)}
500		 after
501		     put(eclectic, foo(Y))
502		 end} of
503		{Done,Z} -> {value,Z};
504		Z -> {caught,Z}
505	    end,
506    {Catch,erase(eclectic)}.
507
508
509
510rethrow(Conf) when is_list(Conf) ->
511    V = {a,[b,{c,self()},make_ref]},
512    {value2,value1} =
513	rethrow_1({value,V}, V),
514    {caught2,{error,V}} =
515	rethrow_2({error,V}, undefined),
516    {caught2,{exit,V}} =
517	rethrow_1({exit,V}, error),
518    {caught2,{throw,V}} =
519	rethrow_1({throw,V}, undefined),
520    {caught2,{throw,V}} =
521	rethrow_2({throw,V}, undefined),
522    {caught2,{error,badarith}} =
523	rethrow_1({'add',{0,a}}, throw),
524    {caught2,{error,function_clause}} =
525	rethrow_2(function_clause, undefined),
526    {caught2,{error,{try_clause,V}}} =
527	rethrow_1({value,V}, exit),
528    {value2,{caught1,V}} =
529	rethrow_1({error,V}, error),
530    {value2,{caught1,V}} =
531	rethrow_1({exit,V}, exit),
532    {value2,caught1} =
533	rethrow_2({throw,V}, V),
534    ok.
535
536rethrow_1(X, C1) ->
537    try try foo(X) of
538            C1 -> value1
539        catch
540            C1:D1 -> {caught1,D1}
541        end of
542        V2 -> {value2,V2}
543    catch
544        C2:D2 -> {caught2,{C2,D2}}
545    end.
546
547rethrow_2(X, C1) ->
548    try try foo(X) of
549            C1 -> value1
550        catch
551            C1 -> caught1 % Implicit class throw:
552        end of
553        V2 -> {value2,V2}
554    catch
555        C2:D2 -> {caught2,{C2,D2}}
556    end.
557
558
559
560nested_of(Conf) when is_list(Conf) ->
561    V = {[self()|make_ref()],1.4142136},
562    {{value,{value1,{V,x2}}},
563     {V,x3},
564     {V,x4},
565     finalized} =
566	nested_of_1({{value,{V,x1}},void,{V,x1}},
567		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
568    {{caught,{throw,{V,x2}}},
569     {V,x3},
570     {V,x4},
571     finalized} =
572	nested_of_1({{value,{V,x1}},void,{V,x1}},
573		    {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
574    {{caught,{error,badarith}},
575     undefined,
576     {V,x4},
577     finalized} =
578	nested_of_1({{value,{V,x1}},void,{V,x1}},
579		    {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
580    {{caught,{error,badarith}},
581     undefined,
582     undefined,
583     finalized} =
584	nested_of_1({{value,{V,x1}},void,{V,x1}},
585		    {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
586    %%
587    {{caught,{error,{try_clause,{V,x1}}}},
588     {V,x3},
589     {V,x4},
590     finalized} =
591	nested_of_1({{value,{V,x1}},void,try_clause},
592		    void, {value,{V,x3}}, {value,{V,x4}}),
593    {{caught,{exit,{V,x3}}},
594     undefined,
595     {V,x4},
596     finalized} =
597	nested_of_1({{value,{V,x1}},void,try_clause},
598		    void, {exit,{V,x3}}, {value,{V,x4}}),
599    {{caught,{throw,{V,x4}}},
600     undefined,
601     undefined,
602     finalized} =
603	nested_of_1({{value,{V,x1}},void,try_clause},
604		    void, {exit,{V,x3}}, {throw,{V,x4}}),
605    %%
606    {{value,{caught1,{V,x2}}},
607     {V,x3},
608     {V,x4},
609     finalized} =
610	nested_of_1({{error,{V,x1}},error,{V,x1}},
611		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
612    {{caught,{error,badarith}},
613     {V,x3},
614     {V,x4},
615     finalized} =
616	nested_of_1({{error,{V,x1}},error,{V,x1}},
617		    {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
618    {{caught,{error,badarith}},
619     undefined,
620     {V,x4},
621     finalized} =
622	nested_of_1({{error,{V,x1}},error,{V,x1}},
623		    {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
624    {{caught,{error,badarg}},
625     undefined,
626     undefined,
627     finalized} =
628	nested_of_1({{error,{V,x1}},error,{V,x1}},
629		    {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
630    %%
631    {{caught,{error,badarith}},
632     {V,x3},
633     {V,x4},
634     finalized} =
635	nested_of_1({{'add',{2,c}},rethrow,void},
636		    void, {value,{V,x3}}, {value,{V,x4}}),
637    {{caught,{error,badarg}},
638     undefined,
639     {V,x4},
640     finalized} =
641	nested_of_1({{'add',{2,c}},rethrow,void},
642		    void, {'abs',V}, {value,{V,x4}}),
643    {{caught,{error,function_clause}},
644     undefined,
645     undefined,
646     finalized} =
647	nested_of_1({{'add',{2,c}},rethrow,void},
648		    void, {'abs',V}, function_clause),
649    ok.
650
651nested_of_1({X1,C1,V1},
652	    X2, X3, X4) ->
653    erase(nested3),
654    erase(nested4),
655    erase(nested),
656    Self = self(),
657    Try =
658	try
659            try self()
660            of
661                Self ->
662                    try
663                        foo(X1)
664	            of
665	                V1 -> {value1,foo(X2)}
666                    catch
667                        C1:V1 -> {caught1,foo(X2)}
668	            after
669                        put(nested3, foo(X3))
670                    end
671            after
672                put(nested4, foo(X4))
673            end
674        of
675            V -> {value,V}
676        catch
677            C:D -> {caught,{C,D}}
678        after
679            put(nested, finalized)
680	end,
681    {Try,erase(nested3),erase(nested4),erase(nested)}.
682
683
684
685nested_catch(Conf) when is_list(Conf) ->
686    V = {[make_ref(),1.4142136,self()]},
687    {{value,{value1,{V,x2}}},
688     {V,x3},
689     {V,x4},
690     finalized} =
691	nested_catch_1({{value,{V,x1}},void,{V,x1}},
692		       {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
693    {{caught,{throw,{V,x2}}},
694     {V,x3},
695     {V,x4},
696     finalized} =
697	nested_catch_1({{value,{V,x1}},void,{V,x1}},
698		       {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
699    {{caught,{error,badarith}},
700     undefined,
701     {V,x4},
702     finalized} =
703	nested_catch_1({{value,{V,x1}},void,{V,x1}},
704		       {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
705    {{caught,{error,badarith}},
706     undefined,
707     undefined,
708     finalized} =
709	nested_catch_1({{value,{V,x1}},void,{V,x1}},
710		       {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
711    %%
712    {{caught,{error,{try_clause,{V,x1}}}},
713     {V,x3},
714     {V,x4},
715     finalized} =
716	nested_catch_1({{value,{V,x1}},void,try_clause},
717		       void, {value,{V,x3}}, {value,{V,x4}}),
718    {{caught,{exit,{V,x3}}},
719     undefined,
720     {V,x4},
721     finalized} =
722	nested_catch_1({{value,{V,x1}},void,try_clause},
723		       void, {exit,{V,x3}}, {value,{V,x4}}),
724    {{caught,{throw,{V,x4}}},
725     undefined,
726     undefined,
727     finalized} =
728	nested_catch_1({{value,{V,x1}},void,try_clause},
729		       void, {exit,{V,x3}}, {throw,{V,x4}}),
730    %%
731    {{value,{caught1,{V,x2}}},
732     {V,x3},
733     {V,x4},
734     finalized} =
735	nested_catch_1({{error,{V,x1}},error,{V,x1}},
736		       {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
737    {{caught,{error,badarith}},
738     {V,x3},
739     {V,x4},
740     finalized} =
741	nested_catch_1({{error,{V,x1}},error,{V,x1}},
742		       {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
743    {{caught,{error,badarith}},
744     undefined,
745     {V,x4},
746     finalized} =
747	nested_catch_1({{error,{V,x1}},error,{V,x1}},
748		       {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
749    {{caught,{error,badarg}},
750     undefined,
751     undefined,
752     finalized} =
753	nested_catch_1({{error,{V,x1}},error,{V,x1}},
754		       {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
755    %%
756    {{caught,{error,badarith}},
757     {V,x3},
758     {V,x4},
759     finalized} =
760	nested_catch_1({{'add',{2,c}},rethrow,void},
761		       void, {value,{V,x3}}, {value,{V,x4}}),
762    {{caught,{error,badarg}},
763     undefined,
764     {V,x4},
765     finalized} =
766	nested_catch_1({{'add',{2,c}},rethrow,void},
767		       void, {'abs',V}, {value,{V,x4}}),
768    {{caught,{error,function_clause}},
769     undefined,
770     undefined,
771     finalized} =
772	nested_catch_1({{'add',{2,c}},rethrow,void},
773		       void, {'abs',V}, function_clause),
774    ok.
775
776nested_catch_1({X1,C1,V1},
777	    X2, X3, X4) ->
778    erase(nested3),
779    erase(nested4),
780    erase(nested),
781    Throw = make_ref(),
782    Try =
783	try
784            try throw(Throw)
785            catch
786		Throw ->
787                    try
788                        foo(X1)
789	            of
790	                V1 -> {value1,foo(X2)}
791                    catch
792                        C1:V1 -> {caught1,foo(X2)}
793	            after
794                        put(nested3, foo(X3))
795                    end
796            after
797                put(nested4, foo(X4))
798            end
799        of
800            V -> {value,V}
801        catch
802            C:D -> {caught,{C,D}}
803        after
804            put(nested, finalized)
805	end,
806    {Try,erase(nested3),erase(nested4),erase(nested)}.
807
808
809
810nested_after(Conf) when is_list(Conf) ->
811    V = [{make_ref(),1.4142136,self()}],
812    {value,
813	   {V,x3},
814	   {value1,{V,x2}},
815	   finalized} =
816	nested_after_1({{value,{V,x1}},void,{V,x1}},
817		       {value,{V,x2}}, {value,{V,x3}}),
818    {{caught,{error,{V,x2}}},
819	   {V,x3},
820	   undefined,
821	   finalized} =
822	nested_after_1({{value,{V,x1}},void,{V,x1}},
823		       {error,{V,x2}}, {value,{V,x3}}),
824    {{caught,{exit,{V,x3}}},
825	   undefined,
826	   undefined,
827	   finalized} =
828	nested_after_1({{value,{V,x1}},void,{V,x1}},
829		       {error,{V,x2}}, {exit,{V,x3}}),
830    %%
831    {{caught,{error,{try_clause,{V,x1}}}},
832	   {V,x3},
833	   undefined,
834	   finalized} =
835	nested_after_1({{value,{V,x1}},void,try_clause},
836		       void, {value,{V,x3}}),
837    {{caught,{error,badarith}},
838	   undefined,
839	   undefined,
840	   finalized} =
841	nested_after_1({{value,{V,x1}},void,try_clause},
842		       void, {'div',{17,0}}),
843    %%
844    {value,
845	   {V,x3},
846	   {caught1,{V,x2}},
847	   finalized} =
848	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
849		       {value,{V,x2}}, {value,{V,x3}}),
850    {{caught,{error,badarith}},
851	   {V,x3},
852	   undefined,
853	   finalized} =
854	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
855		       {'add',{a,b}}, {value,{V,x3}}),
856    {{caught,{error,badarg}},
857	   undefined,
858	   undefined,
859	   finalized} =
860	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
861		       {'add',{a,b}}, {'abs',V}),
862    %%
863    {{caught,{throw,{V,x1}}},
864	   {V,x3},
865	   undefined,
866	   finalized} =
867	nested_after_1({{throw,{V,x1}},rethrow,void},
868		       void, {value,{V,x3}}),
869    {{caught,{error,badarith}},
870	   undefined,
871	   undefined,
872	   finalized} =
873	nested_after_1({{throw,{V,x1}},rethrow,void},
874		       void, {'div',{1,0}}),
875    ok.
876
877nested_after_1({X1,C1,V1},
878	    X2, X3) ->
879    erase(nested3),
880    erase(nested4),
881    erase(nested),
882    Self = self(),
883    Try =
884	try
885            try self()
886            after
887                After =
888                    try
889                        foo(X1)
890	            of
891	                V1 -> {value1,foo(X2)}
892                    catch
893                        C1:V1 -> {caught1,foo(X2)}
894	            after
895                        put(nested3, foo(X3))
896                    end,
897                put(nested4, After)
898            end
899        of
900            Self -> value
901        catch
902            C:D -> {caught,{C,D}}
903        after
904            put(nested, finalized)
905	end,
906    {Try,erase(nested3),erase(nested4),erase(nested)}.
907
908
909
910nested_horrid(Config) when is_list(Config) ->
911    {[true,true],{[true,1.0],1.0}} =
912	nested_horrid_1({true,void,void}, 1.0),
913    ok.
914
915nested_horrid_1({X1,C1,V1}, X2) ->
916    try A1 = [X1,X1],
917	B1 = if X1 ->
918		     A2 = [X1,X2],
919		     B2 = foo(X2),
920		     {A2,B2};
921		true ->
922		     A3 = [X2,X1],
923		     B3 = foo(X2),
924		     {A3,B3}
925	     end,
926	{A1,B1}
927    catch
928	C1:V1 -> caught1
929    end.
930
931
932
933foo({value,Value}) -> Value;
934foo({'div',{A,B}}) ->
935    my_div(A, B);
936foo({'add',{A,B}}) ->
937    my_add(A, B);
938foo({'abs',X}) ->
939    my_abs(X);
940foo({error,Error}) ->
941    erlang:error(Error);
942foo({throw,Throw}) ->
943    erlang:throw(Throw);
944foo({exit,Exit}) ->
945    erlang:exit(Exit);
946foo({raise,{Class,Reason}}) ->
947    erlang:raise(Class, Reason);
948foo(Term) when not is_atom(Term) -> Term.
949%%foo(Atom) when is_atom(Atom) -> % must not be defined!
950
951my_div(A, B) ->
952    A div B.
953
954my_add(A, B) ->
955    A + B.
956
957my_abs(X) -> abs(X).
958
959
960last_call_optimization(Config) when is_list(Config) ->
961    error = in_tail(dum),
962    StkSize0 = in_tail(0),
963    StkSize = in_tail(50000),
964    io:format("StkSize0 = ~p", [StkSize0]),
965    io:format("StkSize  = ~p", [StkSize]),
966    StkSize = StkSize0,
967    ok.
968
969in_tail(E) ->
970    try erlang:abs(E) of
971        T ->
972	    A = id([]),
973	    B = id([]),
974	    C = id([]),
975	    id([A,B,C]),
976	    do_tail(T)
977    catch error:badarg -> error
978    end.
979
980do_tail(0) ->
981    process_info(self(), stack_size);
982do_tail(N) ->
983    in_tail(N-1).
984
985bool(Config) when is_list(Config) ->
986    ok = do_bool(false, false),
987    error = do_bool(false, true),
988    error = do_bool(true, false),
989    error = do_bool(true, true),
990    error = do_bool(true, blurf),
991    {'EXIT',_} = (catch do_bool(blurf, false)),
992    ok.
993
994%% The following function used to cause a crash in beam_bool.
995do_bool(A0, B) ->
996    A = not A0,
997    try
998	id(42),
999	if
1000	    A, not B -> ok
1001	end
1002    catch
1003	_:_ ->
1004	    error
1005    end.
1006
1007plain_catch_coverage(Config) when is_list(Config) ->
1008    %% Cover some code in beam_block:alloc_may_pass/1.
1009    {a,[42]} = do_plain_catch_list(42).
1010
1011do_plain_catch_list(X) ->
1012    B = [X],
1013    catch id({a,B}).
1014
1015andalso_orelse(Config) when is_list(Config) ->
1016    {2,{a,42}} = andalso_orelse_1(true, {a,42}),
1017    {b,{b}} = andalso_orelse_1(false, {b}),
1018    {catched,no_tuple} = andalso_orelse_1(false, no_tuple),
1019
1020    ok = andalso_orelse_2({type,[a]}),
1021    also_ok = andalso_orelse_2({type,[]}),
1022    also_ok = andalso_orelse_2({type,{a}}),
1023    ok.
1024
1025andalso_orelse_1(A, B) ->
1026    {try
1027	 if
1028	     A andalso element(1, B) =:= a ->
1029		 tuple_size(B);
1030	     true ->
1031		 element(1, B)
1032	 end
1033     catch error:_ ->
1034	     catched
1035     end,B}.
1036
1037andalso_orelse_2({Type,Keyval}) ->
1038   try
1039       if is_atom(Type) andalso length(Keyval) > 0 -> ok;
1040          true -> also_ok
1041       end
1042   catch
1043       _:_ -> fail
1044   end.
1045
1046zero() ->
1047    0.0.
1048
1049get_in_try(_) ->
1050    undefined = get_valid_line([a], []),
1051    ok.
1052
1053get_valid_line([_|T]=Path, Annotations) ->
1054    try
1055        get(Path)
1056	%% beam_dead used to optimize away an assignment to {y,1}
1057	%% because it didn't appear to be used.
1058    catch
1059        _:not_found ->
1060            get_valid_line(T, Annotations)
1061    end.
1062
1063hockey(_) ->
1064    {'EXIT',{{badmatch,_},[_|_]}} = (catch hockey()),
1065    ok.
1066
1067hockey() ->
1068    %% beam_jump used to generate a call into the try block.
1069    %% beam_validator disapproved.
1070    receive _ -> (b = fun() -> ok end)
1071    + hockey, +x after 0 -> ok end, try (a = fun() -> ok end) + hockey, +
1072    y catch _ -> ok end.
1073
1074
1075-record(state, {foo}).
1076
1077handle_info(_Config) ->
1078    do_handle_info({foo}, #state{}),
1079    ok.
1080
1081do_handle_info({_}, State) ->
1082   handle_info_ok(),
1083   State#state{foo = bar},
1084   case ok of
1085   _ ->
1086     case catch handle_info_ok() of
1087     ok ->
1088       {stop, State}
1089     end
1090   end;
1091do_handle_info(_, State) ->
1092   (catch begin
1093     handle_info_ok(),
1094     State#state{foo = bar}
1095   end),
1096   case ok of
1097   _ ->
1098     case catch handle_info_ok() of
1099     ok ->
1100       {stop, State}
1101     end
1102   end.
1103
1104handle_info_ok() -> ok.
1105
1106'catch_in_catch'(_Config) ->
1107    process_flag(trap_exit, true),
1108    Pid = spawn_link(fun() ->
1109			     catch_in_catch_init(x),
1110			     exit(good_exit)
1111		     end),
1112    receive
1113	{'EXIT',Pid,good_exit} ->
1114	    ok;
1115	Other ->
1116	    io:format("Unexpected: ~p\n", [Other]),
1117	    error
1118    after 32000 ->
1119	    io:format("No message received\n"),
1120	    error
1121    end.
1122
1123'catch_in_catch_init'(Param) ->
1124    process_flag(trap_exit, true),
1125    %% The catches were improperly nested, causing a "No catch found" crash.
1126    (catch begin
1127           id(Param),
1128           (catch exit(bar))
1129       end
1130    ),
1131    ignore.
1132
1133grab_bag(_Config) ->
1134    %% Thanks to Martin Bjorklund.
1135    _ = fun() -> ok end,
1136    try
1137	fun() -> ok end
1138    after
1139	fun({A, B}) -> A + B end
1140    end,
1141
1142    %% Thanks to Tim Rath.
1143    A = {6},
1144    try
1145	io:fwrite("")
1146    after
1147	fun () ->
1148		fun () -> {_} = A end
1149	end
1150    end,
1151
1152    %% Unnecessary catch.
1153    22 = (catch 22),
1154
1155    fun() ->
1156            F = grab_bag_1(any),
1157            true = is_function(F, 1)
1158    end(),
1159
1160    <<>> = grab_bag_2(whatever),
1161
1162    {'EXIT',_} = (catch grab_bag_3()),
1163
1164    ok.
1165
1166grab_bag_1(V) ->
1167    %% V will be stored in y0.
1168    try
1169        receive
1170        after 0 ->
1171                %% y0 will be re-used for the catch tag.
1172                %% This is safe, because there are no instructions
1173                %% that can raise an exception.
1174                catch 22
1175        end,
1176        %% beam_validator incorrectly assumed that the make_fun2
1177        %% instruction could raise an exception and end up at
1178        %% the catch part of the try.
1179        fun id/1
1180    catch
1181        %% Never reached, because nothing in the try body raises any
1182        %% exception.
1183        _:V ->
1184            ok
1185    end.
1186
1187grab_bag_2(V) ->
1188    try
1189        %% y0 will be re-used for the catch tag.
1190        %% This is safe, because there are no instructions
1191        %% that can raise an exception.
1192        catch 22,
1193
1194        %% beam_validator incorrectly assumed that the bs_init_writable
1195        %% instruction could raise an exception and end up at
1196        %% the catch part of the try.
1197        <<0 || [], #{} <- []>>
1198    catch
1199        %% Never reached, because nothing in the try body raises any
1200        %% exception.
1201        error:_ ->
1202            V
1203    end.
1204
1205grab_bag_3() ->
1206    try 2 of
1207        true ->
1208            <<
1209              "" || [V0] = door
1210            >>
1211    catch
1212        error:true:V0 ->
1213            []
1214            %% The default clause here (which re-throws the exception)
1215            %% would not return two values as expected.
1216    end =:= (V0 = 42).
1217
1218stacktrace(_Config) ->
1219    V = [make_ref()|self()],
1220    case ?MODULE:module_info(native) of
1221        false ->
1222            {value2,{caught1,badarg,[{erlang,abs,[V],_}|_]}} =
1223                stacktrace_1({'abs',V}, error, {value,V}),
1224            {caught2,{error,badarith},[{erlang,'+',[0,a],_},
1225                                       {?MODULE,my_add,2,_}|_]} =
1226                stacktrace_1({'div',{1,0}}, error, {'add',{0,a}});
1227        true ->
1228            {value2,{caught1,badarg,[{?MODULE,my_abs,1,_}|_]}} =
1229                stacktrace_1({'abs',V}, error, {value,V}),
1230            {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]} =
1231                stacktrace_1({'div',{1,0}}, error, {'add',{0,a}})
1232    end,
1233    {caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]} =
1234        stacktrace_1({value,V}, error, {value,V}),
1235    {caught2,{throw,V},[{?MODULE,foo,1,_}|_]} =
1236        stacktrace_1({value,V}, error, {throw,V}),
1237
1238    try
1239        stacktrace_2()
1240    catch
1241        error:{badmatch,_}:Stk2 ->
1242            [{?MODULE,stacktrace_2,0,_},
1243             {?MODULE,stacktrace,1,_}|_] = Stk2,
1244            ok
1245    end,
1246
1247    try
1248        stacktrace_3(a, b)
1249    catch
1250        error:function_clause:Stk3 ->
1251            case lists:module_info(native) of
1252                false ->
1253                    [{lists,prefix,[a,b],_}|_] = Stk3;
1254                true ->
1255                    [{lists,prefix,2,_}|_] = Stk3
1256            end
1257    end,
1258
1259    try
1260        throw(x)
1261    catch
1262        throw:x:IntentionallyUnused ->
1263            ok
1264    end.
1265
1266stacktrace_1(X, C1, Y) ->
1267    try try foo(X) of
1268            C1 -> value1
1269        catch
1270            C1:D1:Stk1 ->
1271                {caught1,D1,Stk1}
1272        after
1273            foo(Y)
1274        end of
1275        V2 -> {value2,V2}
1276    catch
1277        C2:D2:Stk2 ->
1278            {caught2,{C2,D2},Stk2}
1279    end.
1280
1281stacktrace_2() ->
1282    ok = erlang:process_info(self(), current_function),
1283    ok.
1284
1285stacktrace_3(A, B) ->
1286    {ok,lists:prefix(A, B)}.
1287
1288nested_stacktrace(_Config) ->
1289    V = [{make_ref()}|[self()]],
1290    value1 = nested_stacktrace_1({{value,{V,x1}},void,{V,x1}},
1291                                 {void,void,void}),
1292    case ?MODULE:module_info(native) of
1293        false ->
1294            {caught1,
1295             [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
1296             value2} =
1297                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1298                                    {{value,{V,x2}},void,{V,x2}}),
1299            {caught1,
1300             [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
1301             {caught2,[{erlang,abs,[V],_}|_]}} =
1302                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1303                                    {{'abs',V},error,badarg});
1304        true ->
1305            {caught1,
1306             [{?MODULE,my_add,2,_}|_],
1307             value2} =
1308                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1309                                    {{value,{V,x2}},void,{V,x2}}),
1310            {caught1,
1311             [{?MODULE,my_add,2,_}|_],
1312             {caught2,[{?MODULE,my_abs,1,_}|_]}} =
1313                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1314                                    {{'abs',V},error,badarg})
1315    end,
1316    ok.
1317
1318nested_stacktrace_1({X1,C1,V1}, {X2,C2,V2}) ->
1319    try foo(X1) of
1320        V1 -> value1
1321    catch
1322        C1:V1:S1 ->
1323            T2 = try foo(X2) of
1324                     V2 -> value2
1325                 catch
1326                     C2:V2:S2 ->
1327                         {caught2,S2}
1328                 end,
1329            {caught1,S1,T2}
1330    end.
1331
1332raise(_Config) ->
1333    test_raise(fun() -> exit({exit,tuple}) end),
1334    test_raise(fun() -> abs(id(x)) end),
1335    test_raise(fun() -> throw({was,thrown}) end),
1336
1337    badarg = bad_raise(fun() -> abs(id(x)) end),
1338
1339    error = stk_used_in_bin_size(<<0:42>>),
1340    ok.
1341
1342stk_used_in_bin_size(Bin) ->
1343    try
1344        throw(fail)
1345    catch
1346        throw:fail:Stk ->
1347            %% The compiler would crash because the building of the
1348            %% stacktrack was sunk into each case arm.
1349            case Bin of
1350                <<0:Stk>> -> ok;
1351                _ -> error
1352            end
1353    end.
1354
1355bad_raise(Expr) ->
1356    try
1357        Expr()
1358    catch
1359        _:E:Stk ->
1360            erlang:raise(bad_class, E, Stk)
1361    end.
1362
1363test_raise(Expr) ->
1364    test_raise_1(Expr),
1365    test_raise_2(Expr),
1366    test_raise_3(Expr),
1367    test_raise_4(Expr).
1368
1369test_raise_1(Expr) ->
1370    erase(exception),
1371    try
1372        do_test_raise_1(Expr)
1373    catch
1374        C:E:Stk ->
1375            {C,E,Stk} = erase(exception)
1376    end.
1377
1378do_test_raise_1(Expr) ->
1379    try
1380        Expr()
1381    catch
1382        C:E:Stk ->
1383            %% Here the stacktrace must be built.
1384            put(exception, {C,E,Stk}),
1385            erlang:raise(C, E, Stk)
1386    end.
1387
1388test_raise_2(Expr) ->
1389    erase(exception),
1390    try
1391        do_test_raise_2(Expr)
1392    catch
1393        C:E:Stk ->
1394            {C,E} = erase(exception),
1395            try
1396                Expr()
1397            catch
1398                _:_:S ->
1399                    [StkTop|_] = S,
1400                    [StkTop|_] = Stk
1401            end
1402    end.
1403
1404do_test_raise_2(Expr) ->
1405    try
1406        Expr()
1407    catch
1408        C:E:Stk ->
1409            %% Here it is possible to replace erlang:raise/3 with
1410            %% the raw_raise/3 instruction since the stacktrace is
1411            %% not actually used.
1412            put(exception, {C,E}),
1413            erlang:raise(C, E, Stk)
1414    end.
1415
1416test_raise_3(Expr) ->
1417    try
1418        do_test_raise_3(Expr)
1419    catch
1420        exit:{exception,C,E}:Stk ->
1421            try
1422                Expr()
1423            catch
1424                C:E:S ->
1425                    [StkTop|_] = S,
1426                    [StkTop|_] = Stk
1427            end
1428    end.
1429
1430do_test_raise_3(Expr) ->
1431    try
1432        Expr()
1433    catch
1434        C:E:Stk ->
1435            %% Here it is possible to replace erlang:raise/3 with
1436            %% the raw_raise/3 instruction since the stacktrace is
1437            %% not actually used.
1438            erlang:raise(exit, {exception,C,E}, Stk)
1439    end.
1440
1441test_raise_4(Expr) ->
1442    try
1443        do_test_raise_4(Expr)
1444    catch
1445        exit:{exception,C,E,StkTerm}:Stk ->
1446            %% it's not allowed to do the matching directly in the clause head
1447            true = (Stk =:= StkTerm),
1448            try
1449                Expr()
1450            catch
1451                C:E:S ->
1452                    [StkTop|_] = S,
1453                    [StkTop|_] = Stk
1454            end
1455    end.
1456
1457do_test_raise_4(Expr) ->
1458    try
1459        Expr()
1460    catch
1461        C:E:Stk ->
1462            %% Here the stacktrace must be built.
1463            erlang:raise(exit, {exception,C,E,Stk}, Stk)
1464    end.
1465
1466no_return_in_try_block(Config) when is_list(Config) ->
1467    1.0 = no_return_in_try_block_1(0),
1468    1.0 = no_return_in_try_block_1(0.0),
1469
1470    gurka = no_return_in_try_block_1(gurka),
1471    [] = no_return_in_try_block_1([]),
1472
1473    ok.
1474
1475no_return_in_try_block_1(H) ->
1476    try
1477        Float = if
1478                    is_number(H) -> float(H);
1479                    true -> no_return()
1480                end,
1481        Float + 1
1482    catch
1483        throw:no_return -> H
1484    end.
1485
1486no_return() -> throw(no_return).
1487
1488expression_export(_Config) ->
1489    42 = expr_export_1(),
1490    42 = expr_export_2(),
1491
1492    42 = expr_export_3(fun() -> bar end),
1493    beer = expr_export_3(fun() -> pub end),
1494    {error,failed} = expr_export_3(fun() -> error(failed) end),
1495    is_42 = expr_export_3(fun() -> 42 end),
1496    no_good = expr_export_3(fun() -> bad end),
1497
1498    <<>> = expr_export_4(<<1:32>>),
1499    <<"abcd">> = expr_export_4(<<2:32,"abcd">>),
1500    no_match = expr_export_4(<<0:32>>),
1501    no_match = expr_export_4(<<777:32>>),
1502
1503    {1,2,3} = expr_export_5(),
1504    ok.
1505
1506expr_export_1() ->
1507    try Bar = 42 of
1508        _ -> Bar
1509    after
1510        ok
1511    end.
1512
1513expr_export_2() ->
1514    try Bar = 42 of
1515        _ -> Bar
1516    catch
1517        _:_ ->
1518            error
1519    end.
1520
1521expr_export_3(F) ->
1522    try
1523        Bar = 42,
1524        F()
1525    of
1526        bar -> Bar;
1527        pub -> beer;
1528        Bar -> is_42;
1529        _ -> no_good
1530    catch
1531        error:Reason ->
1532            {error,Reason}
1533    end.
1534
1535expr_export_4(Bin) ->
1536    try
1537        SzSz = id(32),
1538        Bin
1539    of
1540        <<Sz:SzSz,Tail:(4*Sz-4)/binary>> -> Tail;
1541        <<_/binary>> -> no_match
1542    after
1543        ok
1544    end.
1545
1546expr_export_5() ->
1547    try
1548        X = 1,
1549        Z = 3,
1550        Y = 2
1551    of
1552        2 -> {X,Y,Z}
1553    after
1554        ok
1555    end.
1556
1557%% GH-4953: Type inference in throw optimization could crash in rare
1558%% circumstances when a thrown type conflicted with one that was matched in
1559%% a catch clause.
1560throw_opt_crash(_Config) ->
1561    try
1562        throw_opt_crash_1(id(false), {pass, id(b), id(c)}),
1563        throw_opt_crash_1(id(false), {crash, id(b)}),
1564        ok
1565    catch
1566        throw:{pass, B, C} ->
1567            {error, gurka, {B, C}};
1568        throw:{beta, B, C} ->
1569            {error, gaffel, {B, C}};
1570        throw:{gamma, B, C} ->
1571            {error, grammofon, {B, C}}
1572    end.
1573
1574throw_opt_crash_1(true, {_, _ ,_}=Term) ->
1575    throw(Term);
1576throw_opt_crash_1(true, {_, _}=Term) ->
1577    throw(Term);
1578throw_opt_crash_1(false, _Term) ->
1579    ok.
1580
1581coverage(_Config) ->
1582    {'EXIT',{{badfun,true},[_|_]}} = (catch coverage_1()),
1583    ok = coverage_ssa_throw(),
1584    error = coverage_pre_codegen(),
1585    ok.
1586
1587%% Cover some code in beam_trim.
1588coverage_1() ->
1589    try
1590        true
1591    catch
1592        law:business ->
1593            program
1594    after
1595        head
1596    end(0),
1597    if
1598        [2 or 1] ->
1599            true
1600    end.
1601
1602%% Cover some code in beam_ssa_throw.
1603coverage_ssa_throw() ->
1604    cst_trivial(),
1605    cst_raw(),
1606    cst_stacktrace(),
1607    cst_types(),
1608
1609    ok.
1610
1611cst_trivial() ->
1612    %% never inspects stacktrace
1613    try
1614        cst_trivial_1()
1615    catch
1616        _C:_R:_S ->
1617            ok
1618    end.
1619
1620cst_trivial_1() -> throw(id(gurka)).
1621
1622cst_types() ->
1623    %% type tests
1624    try
1625        cst_types_1()
1626    catch
1627        throw:Val when is_atom(Val);
1628                       is_bitstring(Val);
1629                       is_binary(Val);
1630                       is_float(Val);
1631                       is_integer(Val);
1632                       is_list(Val);
1633                       is_map(Val);
1634                       is_number(Val);
1635                       is_tuple(Val) ->
1636            ok;
1637        throw:[_|_]=Cons when hd(Cons) =/= gurka;
1638                              tl(Cons) =/= gaffel ->
1639            %% is_nonempty_list, get_hd, get_tl
1640            ok;
1641        throw:Tuple when tuple_size(Tuple) < 5 ->
1642            %% tuple_size
1643            ok
1644    end.
1645
1646cst_types_1() -> throw(id(gurka)).
1647
1648cst_stacktrace() ->
1649    %% build_stacktrace
1650    try
1651        cst_stacktrace_1()
1652    catch
1653        throw:gurka ->
1654            ok;
1655        _C:_R:Stack ->
1656            id(Stack),
1657            ok
1658    end.
1659
1660cst_stacktrace_1() -> throw(id(gurka)).
1661
1662cst_raw() ->
1663    %% raw_raise
1664    try
1665        cst_raw_1()
1666    catch
1667        throw:gurka ->
1668            ok;
1669        _C:_R:Stack ->
1670            erlang:raise(error, dummy, Stack)
1671    end.
1672
1673cst_raw_1() -> throw(id(gurka)).
1674
1675%% Cover some code in beam_ssa_pre_codegen.
1676coverage_pre_codegen() ->
1677    try not (catch 22) of
1678        true ->
1679            ok
1680    catch
1681        _:_ ->
1682            error
1683    end.
1684
1685
1686id(I) -> I.
1687