PageRenderTime 115ms CodeModel.GetById 2ms app.highlight 104ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/compiler/test/trycatch_SUITE.erl

https://github.com/cobusc/otp
Erlang | 1267 lines | 1088 code | 128 blank | 51 comment | 2 complexity | fcbe7792613968b353ffe277b320df26 MD5 | raw file
   1%%
   2%% %CopyrightBegin%
   3%% 
   4%% Copyright Ericsson AB 2003-2018. 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
  32-include_lib("common_test/include/ct.hrl").
  33
  34suite() -> [{ct_hooks,[ts_install_cth]}].
  35
  36all() -> 
  37    [{group,p}].
  38
  39groups() -> 
  40    [{p,[parallel],
  41      [basic,lean_throw,try_of,try_after,catch_oops,
  42       after_oops,eclectic,rethrow,nested_of,nested_catch,
  43       nested_after,nested_horrid,last_call_optimization,
  44       bool,plain_catch_coverage,andalso_orelse,get_in_try,
  45       hockey,handle_info,catch_in_catch,grab_bag,
  46       stacktrace,nested_stacktrace,raise]}].
  47
  48
  49init_per_suite(Config) ->
  50    test_lib:recompile(?MODULE),
  51    Config.
  52
  53end_per_suite(_Config) ->
  54    ok.
  55
  56init_per_group(_GroupName, Config) ->
  57    Config.
  58
  59end_per_group(_GroupName, Config) ->
  60    Config.
  61
  62
  63
  64basic(Conf) when is_list(Conf) ->
  65    2 =
  66	try my_div(4, 2)
  67	catch 
  68            Class:Reason -> {Class,Reason}
  69	end,
  70    error =
  71        try my_div(1, 0)
  72        catch 
  73            error:badarith -> error
  74        end,
  75    error =
  76        try 1.0 / zero()
  77        catch 
  78            error:badarith -> error
  79        end,
  80    ok =
  81        try my_add(53, atom)
  82        catch
  83            error:badarith -> ok
  84        end,
  85    exit_nisse =
  86        try exit(nisse)
  87	catch 
  88            exit:nisse -> exit_nisse
  89        end,
  90    ok =
  91        try throw(kalle)
  92        catch
  93            kalle -> ok
  94        end,
  95
  96    %% Try some stuff where the compiler will optimize away the try.
  97
  98    V = id({a,variable}),
  99    V = try V catch nisse -> error end,
 100    42 = try 42 catch nisse -> error end,
 101    [V] = try [V] catch nisse -> error end,
 102    {ok,V} = try {ok,V} catch nisse -> error end,
 103
 104    %% Same idea, but use an after too.
 105
 106    V = try V catch nisse -> error after after_call() end,
 107    after_clean(),
 108    42 = try 42 after after_call() end,
 109    after_clean(),
 110    [V] = try [V] catch nisse -> error after after_call() end,
 111    after_clean(),
 112    {ok,V} = try {ok,V} after after_call() end,
 113
 114    %% Try/of
 115    ok = try V of
 116	     {a,variable} -> ok
 117	 catch nisse -> erro
 118	 end,
 119
 120    %% Unmatchable clauses.
 121    try
 122        throw(thrown)
 123    catch
 124        {a,b}={a,b,c} ->                        %Intentionally no match.
 125            ok;
 126        thrown ->
 127            ok
 128    end,
 129
 130    ok.
 131
 132after_call() ->
 133    put(basic, after_was_called).
 134
 135after_clean() ->
 136    after_was_called = erase(basic).
 137    
 138
 139lean_throw(Conf) when is_list(Conf) ->
 140    {throw,kalle} =
 141        try throw(kalle)
 142        catch
 143            Kalle -> {throw,Kalle}
 144        end,
 145    {exit,kalle} =
 146        try exit(kalle)
 147        catch
 148            Throw1 -> {throw,Throw1};
 149	    exit:Reason1 -> {exit,Reason1}
 150        end,
 151    {exit,kalle} =
 152        try exit(kalle)
 153        catch
 154	    exit:Reason2 -> {exit,Reason2};
 155            Throw2 -> {throw,Throw2}
 156        end,
 157    {exit,kalle} =
 158        try try exit(kalle)
 159            catch
 160                Throw3 -> {throw,Throw3}
 161            end
 162        catch
 163            exit:Reason3 -> {exit,Reason3}
 164        end,
 165    ok.
 166
 167
 168
 169try_of(Conf) when is_list(Conf) ->
 170    {ok,{some,content}} =
 171	try_of_1({value,{good,{some,content}}}),
 172    {error,[other,content]} =
 173	try_of_1({value,{bad,[other,content]}}),
 174    {caught,{exit,{ex,it,[reason]}}} =
 175	try_of_1({exit,{ex,it,[reason]}}),
 176    {caught,{throw,[term,{in,a,{tuple}}]}} =
 177	try_of_1({throw,[term,{in,a,{tuple}}]}),
 178    {caught,{error,[bad,arg]}} =
 179	try_of_1({error,[bad,arg]}),
 180    {caught,{error,badarith}} =
 181	try_of_1({'div',{1,0}}),
 182    {caught,{error,badarith}} =
 183	try_of_1({'add',{a,0}}),
 184    {caught,{error,badarg}} =
 185	try_of_1({'abs',x}),
 186    {caught,{error,function_clause}} =
 187	try_of_1(illegal),
 188    {error,{try_clause,{some,other_garbage}}} =
 189	try try_of_1({value,{some,other_garbage}})
 190        catch error:Reason -> {error,Reason}
 191        end,
 192    ok.
 193
 194try_of_1(X) ->
 195    try foo(X) of
 196        {good,Y} -> {ok,Y};
 197	{bad,Y} -> {error,Y}
 198    catch
 199	Class:Reason ->
 200             {caught,{Class,Reason}}
 201    end.
 202
 203
 204
 205try_after(Conf) when is_list(Conf) ->
 206    {{ok,[some,value],undefined},finalized} =
 207	try_after_1({value,{ok,[some,value]}},finalized),
 208    {{error,badarith,undefined},finalized} =
 209	try_after_1({'div',{1,0}},finalized),
 210    {{error,badarith,undefined},finalized} =
 211	try_after_1({'add',{1,a}},finalized),
 212    {{error,badarg,undefined},finalized} =
 213	try_after_1({'abs',a},finalized),
 214    {{error,[the,{reason}],undefined},finalized} =
 215	try_after_1({error,[the,{reason}]},finalized),
 216    {{throw,{thrown,[reason]},undefined},finalized} =
 217	try_after_1({throw,{thrown,[reason]}},finalized),
 218    {{exit,{exited,{reason}},undefined},finalized} =
 219	try_after_1({exit,{exited,{reason}}},finalized),
 220    {{error,function_clause,undefined},finalized} =
 221	try_after_1(function_clause,finalized),
 222    ok =
 223	try try_after_1({'add',{1,1}}, finalized)
 224        catch
 225            error:{try_clause,2} -> ok
 226	end,
 227    finalized = erase(try_after),
 228    ok =
 229        try try foo({exit,[reaso,{n}]})
 230            after put(try_after, finalized)
 231            end
 232        catch
 233            exit:[reaso,{n}] -> ok
 234        end,
 235    ok.
 236
 237try_after_1(X, Y) ->
 238    erase(try_after),
 239    Try =
 240        try foo(X) of
 241	    {ok,Value} -> {ok,Value,get(try_after)}
 242        catch
 243	    Reason -> {throw,Reason,get(try_after)};
 244	    error:Reason -> {error,Reason,get(try_after)};
 245	    exit:Reason ->  {exit,Reason,get(try_after)}
 246        after
 247	    put(try_after, Y)
 248        end,
 249    {Try,erase(try_after)}.
 250
 251
 252
 253-ifdef(begone).
 254
 255after_bind(Conf) when is_list(Conf) ->
 256    V = [make_ref(),self()|value],
 257    {value,{value,V}} =
 258	after_bind_1({value,V}, V, {value,V}),
 259    ok.
 260
 261after_bind_1(X, V, Y) ->
 262    try
 263        Try =
 264            try foo(X) of
 265                V -> value
 266            catch
 267                C1:V -> {caught,C1}
 268            after
 269                After = foo(Y)
 270	    end,
 271        {Try,After} 
 272    of
 273        V -> {value,V}
 274    catch
 275        C:D -> {caught,{C,D}}
 276    end.
 277
 278-endif.
 279
 280
 281
 282catch_oops(Conf) when is_list(Conf) ->
 283    V = {v,[a,l|u],{e},self()},
 284    {value,V} = catch_oops_1({value,V}),
 285    {value,1} = catch_oops_1({'div',{1,1}}),
 286    {error,badarith} = catch_oops_1({'div',{1,0}}),
 287    {error,function_clause} = catch_oops_1(function_clause),
 288    {throw,V} = catch_oops_1({throw,V}),
 289    {exit,V} = catch_oops_1({exit,V}),
 290    ok.
 291
 292catch_oops_1(X) ->
 293    Ref = make_ref(),
 294    try try foo({error,Ref})
 295        catch
 296            error:Ref ->
 297	        foo(X)
 298        end of
 299        Value -> {value,Value}
 300    catch
 301        Class:Data -> {Class,Data}
 302    end.
 303
 304
 305
 306after_oops(Conf) when is_list(Conf) ->
 307    V = {self(),make_ref()},
 308    {{value,V},V} = after_oops_1({value,V}, {value,V}),
 309    {{exit,V},V} = after_oops_1({exit,V}, {value,V}),
 310    {{error,V},undefined} = after_oops_1({value,V}, {error,V}),
 311    {{error,function_clause},undefined} =
 312	after_oops_1({exit,V}, function_clause),
 313    ok.
 314
 315after_oops_1(X, Y) ->
 316    erase(after_oops),
 317    Try =
 318        try try foo(X)
 319            after
 320                put(after_oops, foo(Y))
 321            end of
 322            V -> {value,V}
 323        catch
 324            C:D -> {C,D}
 325        end,
 326    {Try,erase(after_oops)}.
 327
 328
 329
 330eclectic(Conf) when is_list(Conf) ->
 331    V = {make_ref(),3.1415926535,[[]|{}]},
 332    {{value,{value,V},V},V} =
 333	eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
 334    {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
 335	eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
 336    {{error,{exit,V},{'EXIT',V}},V} =
 337	eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
 338    {{value,{value,V},V},
 339	   {'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}} =
 340	eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
 341    {{'EXIT',V},V} =
 342	eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
 343    {{error,{'div',{1,0}},{'EXIT',{badarith,[{erlang,'div',[1,0],_},{?MODULE,my_div,2,_}|_]}}},
 344	   {'EXIT',V}} =
 345	eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
 346    {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
 347	   {'EXIT',V}} =
 348	eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
 349    %%
 350    {{value,{value,{value,V},V}},V} =
 351	eclectic_2({value,{value,V}}, undefined, {value,V}),
 352    {{value,{throw,{value,V},V}},V} =
 353	eclectic_2({throw,{value,V}}, throw, {value,V}),
 354    {{caught,{'EXIT',V}},undefined} =
 355	eclectic_2({value,{value,V}}, undefined, {exit,V}),
 356    {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
 357	eclectic_2({error,{value,V}}, throw, {error,V}),
 358    {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
 359	eclectic_2({value,{'abs',V}}, undefined, {value,V}),
 360    {{caught,{'EXIT',{badarith,[{erlang,'+',[0,a],_},{?MODULE,my_add,2,_}|_]}}},V} =
 361	eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
 362    {{caught,{'EXIT',V}},undefined} =
 363	eclectic_2({value,{error,V}}, undefined, {exit,V}),
 364    {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
 365	eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
 366    ok.
 367
 368eclectic_1(X, C, Y) ->
 369    erase(eclectic),
 370    Done = make_ref(),
 371    Try =
 372        try case X of
 373		{catch_foo,V} -> catch {Done,foo(V)};
 374		{foo,V} -> {Done,foo(V)}
 375	    end of
 376            {Done,D} -> {value,D,catch foo(D)};
 377	    {'EXIT',_}=Exit -> Exit;
 378	    D -> {D,catch foo(D)}
 379        catch
 380            C:D -> {C,D,catch foo(D)}
 381        after
 382            put(eclectic, catch foo(Y))
 383        end,
 384    {Try,erase(eclectic)}.
 385
 386eclectic_2(X, C, Y) ->
 387    Done = make_ref(),
 388    erase(eclectic),
 389    Catch =
 390	case 
 391            catch
 392		{Done,
 393		 try foo(X) of
 394		     V -> {value,V,foo(V)}
 395		 catch
 396		     C:D -> {C,D,foo(D)}
 397		 after
 398		     put(eclectic, foo(Y))
 399		 end} of
 400		{Done,Z} -> {value,Z};
 401		Z -> {caught,Z}
 402	    end,
 403    {Catch,erase(eclectic)}.
 404
 405
 406
 407rethrow(Conf) when is_list(Conf) ->
 408    V = {a,[b,{c,self()},make_ref]},
 409    {value2,value1} =
 410	rethrow_1({value,V}, V),
 411    {caught2,{error,V}} =
 412	rethrow_2({error,V}, undefined),
 413    {caught2,{exit,V}} =
 414	rethrow_1({exit,V}, error),
 415    {caught2,{throw,V}} =
 416	rethrow_1({throw,V}, undefined),
 417    {caught2,{throw,V}} =
 418	rethrow_2({throw,V}, undefined),
 419    {caught2,{error,badarith}} =
 420	rethrow_1({'add',{0,a}}, throw),
 421    {caught2,{error,function_clause}} =
 422	rethrow_2(function_clause, undefined),
 423    {caught2,{error,{try_clause,V}}} =
 424	rethrow_1({value,V}, exit),
 425    {value2,{caught1,V}} =
 426	rethrow_1({error,V}, error),
 427    {value2,{caught1,V}} =
 428	rethrow_1({exit,V}, exit),
 429    {value2,caught1} =
 430	rethrow_2({throw,V}, V),
 431    ok.
 432
 433rethrow_1(X, C1) ->
 434    try try foo(X) of
 435            C1 -> value1
 436        catch
 437            C1:D1 -> {caught1,D1}
 438        end of
 439        V2 -> {value2,V2}
 440    catch
 441        C2:D2 -> {caught2,{C2,D2}}
 442    end.
 443
 444rethrow_2(X, C1) ->
 445    try try foo(X) of
 446            C1 -> value1
 447        catch
 448            C1 -> caught1 % Implicit class throw:
 449        end of
 450        V2 -> {value2,V2}
 451    catch
 452        C2:D2 -> {caught2,{C2,D2}}
 453    end.
 454
 455
 456
 457nested_of(Conf) when is_list(Conf) ->
 458    V = {[self()|make_ref()],1.4142136},
 459    {{value,{value1,{V,x2}}},
 460     {V,x3},
 461     {V,x4},
 462     finalized} =
 463	nested_of_1({{value,{V,x1}},void,{V,x1}},
 464		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
 465    {{caught,{throw,{V,x2}}},
 466     {V,x3},
 467     {V,x4},
 468     finalized} =
 469	nested_of_1({{value,{V,x1}},void,{V,x1}},
 470		    {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
 471    {{caught,{error,badarith}},
 472     undefined,
 473     {V,x4},
 474     finalized} =
 475	nested_of_1({{value,{V,x1}},void,{V,x1}},
 476		    {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
 477    {{caught,{error,badarith}},
 478     undefined,
 479     undefined,
 480     finalized} =
 481	nested_of_1({{value,{V,x1}},void,{V,x1}},
 482		    {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
 483    %%
 484    {{caught,{error,{try_clause,{V,x1}}}},
 485     {V,x3},
 486     {V,x4},
 487     finalized} =
 488	nested_of_1({{value,{V,x1}},void,try_clause},
 489		    void, {value,{V,x3}}, {value,{V,x4}}),
 490    {{caught,{exit,{V,x3}}},
 491     undefined,
 492     {V,x4},
 493     finalized} =
 494	nested_of_1({{value,{V,x1}},void,try_clause},
 495		    void, {exit,{V,x3}}, {value,{V,x4}}),
 496    {{caught,{throw,{V,x4}}},
 497     undefined,
 498     undefined,
 499     finalized} =
 500	nested_of_1({{value,{V,x1}},void,try_clause},
 501		    void, {exit,{V,x3}}, {throw,{V,x4}}),
 502    %%
 503    {{value,{caught1,{V,x2}}},
 504     {V,x3},
 505     {V,x4},
 506     finalized} =
 507	nested_of_1({{error,{V,x1}},error,{V,x1}},
 508		    {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
 509    {{caught,{error,badarith}},
 510     {V,x3},
 511     {V,x4},
 512     finalized} =
 513	nested_of_1({{error,{V,x1}},error,{V,x1}},
 514		    {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
 515    {{caught,{error,badarith}},
 516     undefined,
 517     {V,x4},
 518     finalized} =
 519	nested_of_1({{error,{V,x1}},error,{V,x1}},
 520		    {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
 521    {{caught,{error,badarg}},
 522     undefined,
 523     undefined,
 524     finalized} =
 525	nested_of_1({{error,{V,x1}},error,{V,x1}},
 526		    {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
 527    %%
 528    {{caught,{error,badarith}},
 529     {V,x3},
 530     {V,x4},
 531     finalized} =
 532	nested_of_1({{'add',{2,c}},rethrow,void},
 533		    void, {value,{V,x3}}, {value,{V,x4}}),
 534    {{caught,{error,badarg}},
 535     undefined,
 536     {V,x4},
 537     finalized} =
 538	nested_of_1({{'add',{2,c}},rethrow,void},
 539		    void, {'abs',V}, {value,{V,x4}}),
 540    {{caught,{error,function_clause}},
 541     undefined,
 542     undefined,
 543     finalized} =
 544	nested_of_1({{'add',{2,c}},rethrow,void},
 545		    void, {'abs',V}, function_clause),
 546    ok.
 547
 548nested_of_1({X1,C1,V1},
 549	    X2, X3, X4) ->
 550    erase(nested3),
 551    erase(nested4),
 552    erase(nested),
 553    Self = self(),
 554    Try =
 555	try
 556            try self()
 557            of
 558                Self ->
 559                    try 
 560                        foo(X1) 
 561	            of
 562	                V1 -> {value1,foo(X2)}
 563                    catch
 564                        C1:V1 -> {caught1,foo(X2)}
 565	            after
 566                        put(nested3, foo(X3))
 567                    end
 568            after
 569                put(nested4, foo(X4))
 570            end
 571        of
 572            V -> {value,V}
 573        catch
 574            C:D -> {caught,{C,D}}
 575        after
 576            put(nested, finalized)
 577	end,
 578    {Try,erase(nested3),erase(nested4),erase(nested)}.
 579
 580
 581
 582nested_catch(Conf) when is_list(Conf) ->
 583    V = {[make_ref(),1.4142136,self()]},
 584    {{value,{value1,{V,x2}}},
 585     {V,x3},
 586     {V,x4},
 587     finalized} =
 588	nested_catch_1({{value,{V,x1}},void,{V,x1}},
 589		       {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
 590    {{caught,{throw,{V,x2}}},
 591     {V,x3},
 592     {V,x4},
 593     finalized} =
 594	nested_catch_1({{value,{V,x1}},void,{V,x1}},
 595		       {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
 596    {{caught,{error,badarith}},
 597     undefined,
 598     {V,x4},
 599     finalized} =
 600	nested_catch_1({{value,{V,x1}},void,{V,x1}},
 601		       {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}),
 602    {{caught,{error,badarith}},
 603     undefined,
 604     undefined,
 605     finalized} =
 606	nested_catch_1({{value,{V,x1}},void,{V,x1}},
 607		       {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}),
 608    %%
 609    {{caught,{error,{try_clause,{V,x1}}}},
 610     {V,x3},
 611     {V,x4},
 612     finalized} =
 613	nested_catch_1({{value,{V,x1}},void,try_clause},
 614		       void, {value,{V,x3}}, {value,{V,x4}}),
 615    {{caught,{exit,{V,x3}}},
 616     undefined,
 617     {V,x4},
 618     finalized} =
 619	nested_catch_1({{value,{V,x1}},void,try_clause},
 620		       void, {exit,{V,x3}}, {value,{V,x4}}),
 621    {{caught,{throw,{V,x4}}},
 622     undefined,
 623     undefined,
 624     finalized} =
 625	nested_catch_1({{value,{V,x1}},void,try_clause},
 626		       void, {exit,{V,x3}}, {throw,{V,x4}}),
 627    %%
 628    {{value,{caught1,{V,x2}}},
 629     {V,x3},
 630     {V,x4},
 631     finalized} =
 632	nested_catch_1({{error,{V,x1}},error,{V,x1}},
 633		       {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}),
 634    {{caught,{error,badarith}},
 635     {V,x3},
 636     {V,x4},
 637     finalized} =
 638	nested_catch_1({{error,{V,x1}},error,{V,x1}},
 639		       {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}),
 640    {{caught,{error,badarith}},
 641     undefined,
 642     {V,x4},
 643     finalized} =
 644	nested_catch_1({{error,{V,x1}},error,{V,x1}},
 645		       {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}),
 646    {{caught,{error,badarg}},
 647     undefined,
 648     undefined,
 649     finalized} =
 650	nested_catch_1({{error,{V,x1}},error,{V,x1}},
 651		       {'add',{1,c}}, {'div',{17,0}}, {'abs',V}),
 652    %%
 653    {{caught,{error,badarith}},
 654     {V,x3},
 655     {V,x4},
 656     finalized} =
 657	nested_catch_1({{'add',{2,c}},rethrow,void},
 658		       void, {value,{V,x3}}, {value,{V,x4}}),
 659    {{caught,{error,badarg}},
 660     undefined,
 661     {V,x4},
 662     finalized} =
 663	nested_catch_1({{'add',{2,c}},rethrow,void},
 664		       void, {'abs',V}, {value,{V,x4}}),
 665    {{caught,{error,function_clause}},
 666     undefined,
 667     undefined,
 668     finalized} =
 669	nested_catch_1({{'add',{2,c}},rethrow,void},
 670		       void, {'abs',V}, function_clause),
 671    ok.
 672
 673nested_catch_1({X1,C1,V1},
 674	    X2, X3, X4) ->
 675    erase(nested3),
 676    erase(nested4),
 677    erase(nested),
 678    Throw = make_ref(),
 679    Try =
 680	try
 681            try throw(Throw)
 682            catch
 683		Throw ->
 684                    try 
 685                        foo(X1) 
 686	            of
 687	                V1 -> {value1,foo(X2)}
 688                    catch
 689                        C1:V1 -> {caught1,foo(X2)}
 690	            after
 691                        put(nested3, foo(X3))
 692                    end
 693            after
 694                put(nested4, foo(X4))
 695            end
 696        of
 697            V -> {value,V}
 698        catch
 699            C:D -> {caught,{C,D}}
 700        after
 701            put(nested, finalized)
 702	end,
 703    {Try,erase(nested3),erase(nested4),erase(nested)}.
 704
 705
 706
 707nested_after(Conf) when is_list(Conf) ->
 708    V = [{make_ref(),1.4142136,self()}],
 709    {value,
 710	   {V,x3},
 711	   {value1,{V,x2}},
 712	   finalized} =
 713	nested_after_1({{value,{V,x1}},void,{V,x1}},
 714		       {value,{V,x2}}, {value,{V,x3}}),
 715    {{caught,{error,{V,x2}}},
 716	   {V,x3},
 717	   undefined,
 718	   finalized} =
 719	nested_after_1({{value,{V,x1}},void,{V,x1}},
 720		       {error,{V,x2}}, {value,{V,x3}}),
 721    {{caught,{exit,{V,x3}}},
 722	   undefined,
 723	   undefined,
 724	   finalized} =
 725	nested_after_1({{value,{V,x1}},void,{V,x1}},
 726		       {error,{V,x2}}, {exit,{V,x3}}),
 727    %%
 728    {{caught,{error,{try_clause,{V,x1}}}},
 729	   {V,x3},
 730	   undefined,
 731	   finalized} =
 732	nested_after_1({{value,{V,x1}},void,try_clause},
 733		       void, {value,{V,x3}}),
 734    {{caught,{error,badarith}},
 735	   undefined,
 736	   undefined,
 737	   finalized} =
 738	nested_after_1({{value,{V,x1}},void,try_clause},
 739		       void, {'div',{17,0}}),
 740    %%
 741    {value,
 742	   {V,x3},
 743	   {caught1,{V,x2}},
 744	   finalized} =
 745	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
 746		       {value,{V,x2}}, {value,{V,x3}}),
 747    {{caught,{error,badarith}},
 748	   {V,x3},
 749	   undefined,
 750	   finalized} =
 751	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
 752		       {'add',{a,b}}, {value,{V,x3}}),
 753    {{caught,{error,badarg}},
 754	   undefined,
 755	   undefined,
 756	   finalized} =
 757	nested_after_1({{throw,{V,x1}},throw,{V,x1}},
 758		       {'add',{a,b}}, {'abs',V}),
 759    %%
 760    {{caught,{throw,{V,x1}}},
 761	   {V,x3},
 762	   undefined,
 763	   finalized} =
 764	nested_after_1({{throw,{V,x1}},rethrow,void},
 765		       void, {value,{V,x3}}),
 766    {{caught,{error,badarith}},
 767	   undefined,
 768	   undefined,
 769	   finalized} =
 770	nested_after_1({{throw,{V,x1}},rethrow,void},
 771		       void, {'div',{1,0}}),
 772    ok.
 773
 774nested_after_1({X1,C1,V1},
 775	    X2, X3) ->
 776    erase(nested3),
 777    erase(nested4),
 778    erase(nested),
 779    Self = self(),
 780    Try =
 781	try
 782            try self()
 783            after
 784                After =
 785                    try 
 786                        foo(X1) 
 787	            of
 788	                V1 -> {value1,foo(X2)}
 789                    catch
 790                        C1:V1 -> {caught1,foo(X2)}
 791	            after
 792                        put(nested3, foo(X3))
 793                    end,
 794                put(nested4, After)
 795            end
 796        of
 797            Self -> value
 798        catch
 799            C:D -> {caught,{C,D}}
 800        after
 801            put(nested, finalized)
 802	end,
 803    {Try,erase(nested3),erase(nested4),erase(nested)}.
 804
 805
 806
 807nested_horrid(Config) when is_list(Config) ->
 808    {[true,true],{[true,1.0],1.0}} =
 809	nested_horrid_1({true,void,void}, 1.0),
 810    ok.
 811
 812nested_horrid_1({X1,C1,V1}, X2) ->
 813    try A1 = [X1,X1],
 814	B1 = if X1 ->
 815		     A2 = [X1,X2],
 816		     B2 = foo(X2),
 817		     {A2,B2};
 818		true ->
 819		     A3 = [X2,X1],
 820		     B3 = foo(X2),
 821		     {A3,B3}
 822	     end,
 823	{A1,B1}
 824    catch
 825	C1:V1 -> caught1
 826    end.
 827
 828
 829
 830foo({value,Value}) -> Value;
 831foo({'div',{A,B}}) ->
 832    my_div(A, B);
 833foo({'add',{A,B}}) ->
 834    my_add(A, B);
 835foo({'abs',X}) ->
 836    my_abs(X);
 837foo({error,Error}) -> 
 838    erlang:error(Error);
 839foo({throw,Throw}) ->
 840    erlang:throw(Throw);
 841foo({exit,Exit}) ->
 842    erlang:exit(Exit);
 843foo({raise,{Class,Reason}}) ->
 844    erlang:raise(Class, Reason);
 845foo(Term) when not is_atom(Term) -> Term.
 846%%foo(Atom) when is_atom(Atom) -> % must not be defined!
 847
 848my_div(A, B) ->
 849    A div B.
 850
 851my_add(A, B) ->
 852    A + B.
 853
 854my_abs(X) -> abs(X).
 855
 856
 857last_call_optimization(Config) when is_list(Config) ->
 858    error = in_tail(dum),
 859    StkSize0 = in_tail(0),
 860    StkSize = in_tail(50000),
 861    io:format("StkSize0 = ~p", [StkSize0]),
 862    io:format("StkSize  = ~p", [StkSize]),
 863    StkSize = StkSize0,
 864    ok.
 865
 866in_tail(E) ->
 867    try erlang:abs(E) of
 868        T ->
 869	    A = id([]),
 870	    B = id([]),
 871	    C = id([]),
 872	    id([A,B,C]),
 873	    do_tail(T)
 874    catch error:badarg -> error
 875    end.
 876
 877do_tail(0) ->
 878    process_info(self(), stack_size);
 879do_tail(N) ->
 880    in_tail(N-1).
 881
 882bool(Config) when is_list(Config) ->
 883    ok = do_bool(false, false),
 884    error = do_bool(false, true),
 885    error = do_bool(true, false),
 886    error = do_bool(true, true),
 887    error = do_bool(true, blurf),
 888    {'EXIT',_} = (catch do_bool(blurf, false)),
 889    ok.
 890
 891%% The following function used to cause a crash in beam_bool.
 892do_bool(A0, B) ->
 893    A = not A0,
 894    try
 895	id(42),
 896	if
 897	    A, not B -> ok
 898	end
 899    catch
 900	_:_ ->
 901	    error
 902    end.
 903
 904plain_catch_coverage(Config) when is_list(Config) ->
 905    %% Cover some code in beam_block:alloc_may_pass/1.
 906    {a,[42]} = do_plain_catch_list(42).
 907
 908do_plain_catch_list(X) ->
 909    B = [X],
 910    catch id({a,B}).
 911
 912andalso_orelse(Config) when is_list(Config) ->
 913    {2,{a,42}} = andalso_orelse_1(true, {a,42}),
 914    {b,{b}} = andalso_orelse_1(false, {b}),
 915    {catched,no_tuple} = andalso_orelse_1(false, no_tuple),
 916
 917    ok = andalso_orelse_2({type,[a]}),
 918    also_ok = andalso_orelse_2({type,[]}),
 919    also_ok = andalso_orelse_2({type,{a}}),
 920    ok.
 921
 922andalso_orelse_1(A, B) ->
 923    {try
 924	 if
 925	     A andalso element(1, B) =:= a ->
 926		 tuple_size(B);
 927	     true ->
 928		 element(1, B)
 929	 end
 930     catch error:_ ->
 931	     catched
 932     end,B}.
 933
 934andalso_orelse_2({Type,Keyval}) ->
 935   try
 936       if is_atom(Type) andalso length(Keyval) > 0 -> ok;
 937          true -> also_ok
 938       end
 939   catch
 940       _:_ -> fail
 941   end.
 942
 943zero() ->
 944    0.0.
 945
 946get_in_try(_) ->
 947    undefined = get_valid_line([a], []),
 948    ok.
 949
 950get_valid_line([_|T]=Path, Annotations) ->
 951    try
 952        get(Path)
 953	%% beam_dead used to optimize away an assignment to {y,1}
 954	%% because it didn't appear to be used.
 955    catch
 956        _:not_found ->
 957            get_valid_line(T, Annotations)
 958    end.
 959
 960hockey(_) ->
 961    {'EXIT',{{badmatch,_},[_|_]}} = (catch hockey()),
 962    ok.
 963
 964hockey() ->
 965    %% beam_jump used to generate a call into the try block.
 966    %% beam_validator disapproved.
 967    receive _ -> (b = fun() -> ok end)
 968    + hockey, +x after 0 -> ok end, try (a = fun() -> ok end) + hockey, +
 969    y catch _ -> ok end.
 970
 971
 972-record(state, {foo}).
 973
 974handle_info(_Config) ->
 975    do_handle_info({foo}, #state{}),
 976    ok.
 977
 978do_handle_info({_}, State) ->
 979   handle_info_ok(),
 980   State#state{foo = bar},
 981   case ok of
 982   _ ->
 983     case catch handle_info_ok() of
 984     ok ->
 985       {stop, State}
 986     end
 987   end;
 988do_handle_info(_, State) ->
 989   (catch begin
 990     handle_info_ok(),
 991     State#state{foo = bar}
 992   end),
 993   case ok of
 994   _ ->
 995     case catch handle_info_ok() of
 996     ok ->
 997       {stop, State}
 998     end
 999   end.
1000
1001handle_info_ok() -> ok.
1002
1003'catch_in_catch'(_Config) ->
1004    process_flag(trap_exit, true),
1005    Pid = spawn_link(fun() ->
1006			     catch_in_catch_init(x),
1007			     exit(good_exit)
1008		     end),
1009    receive
1010	{'EXIT',Pid,good_exit} ->
1011	    ok;
1012	Other ->
1013	    io:format("Unexpected: ~p\n", [Other]),
1014	    error
1015    after 32000 ->
1016	    io:format("No message received\n"),
1017	    error
1018    end.
1019
1020'catch_in_catch_init'(Param) ->
1021    process_flag(trap_exit, true),
1022    %% The catches were improperly nested, causing a "No catch found" crash.
1023    (catch begin
1024           id(Param),
1025           (catch exit(bar))
1026       end
1027    ),
1028    ignore.
1029
1030grab_bag(_Config) ->
1031    %% Thanks to Martin Bjorklund.
1032    _ = fun() -> ok end,
1033    try
1034	fun() -> ok end
1035    after
1036	fun({A, B}) -> A + B end
1037    end,
1038
1039    %% Thanks to Tim Rath.
1040    A = {6},
1041    try
1042	io:fwrite("")
1043    after
1044	fun () ->
1045		fun () -> {_} = A end
1046	end
1047    end,
1048
1049    %% Unnecessary catch.
1050    22 = (catch 22),
1051
1052    ok.
1053
1054stacktrace(_Config) ->
1055    V = [make_ref()|self()],
1056    case ?MODULE:module_info(native) of
1057        false ->
1058            {value2,{caught1,badarg,[{erlang,abs,[V],_}|_]}} =
1059                stacktrace_1({'abs',V}, error, {value,V}),
1060            {caught2,{error,badarith},[{erlang,'+',[0,a],_},
1061                                       {?MODULE,my_add,2,_}|_]} =
1062                stacktrace_1({'div',{1,0}}, error, {'add',{0,a}});
1063        true ->
1064            {value2,{caught1,badarg,[{?MODULE,my_abs,1,_}|_]}} =
1065                stacktrace_1({'abs',V}, error, {value,V}),
1066            {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]} =
1067                stacktrace_1({'div',{1,0}}, error, {'add',{0,a}})
1068    end,
1069    {caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]} =
1070        stacktrace_1({value,V}, error, {value,V}),
1071    {caught2,{throw,V},[{?MODULE,foo,1,_}|_]} =
1072        stacktrace_1({value,V}, error, {throw,V}),
1073
1074    try
1075        stacktrace_2()
1076    catch
1077        error:{badmatch,_}:Stk2 ->
1078            [{?MODULE,stacktrace_2,0,_},
1079             {?MODULE,stacktrace,1,_}|_] = Stk2,
1080            Stk2 = erlang:get_stacktrace(),
1081            ok
1082    end,
1083
1084    try
1085        stacktrace_3(a, b)
1086    catch
1087        error:function_clause:Stk3 ->
1088            Stk3 = erlang:get_stacktrace(),
1089            case lists:module_info(native) of
1090                false ->
1091                    [{lists,prefix,[a,b],_}|_] = Stk3;
1092                true ->
1093                    [{lists,prefix,2,_}|_] = Stk3
1094            end
1095    end,
1096
1097    try
1098        throw(x)
1099    catch
1100        throw:x:IntentionallyUnused ->
1101            ok
1102    end.
1103
1104stacktrace_1(X, C1, Y) ->
1105    try try foo(X) of
1106            C1 -> value1
1107        catch
1108            C1:D1:Stk1 ->
1109                Stk1 = erlang:get_stacktrace(),
1110                {caught1,D1,Stk1}
1111        after
1112            foo(Y)
1113        end of
1114        V2 -> {value2,V2}
1115    catch
1116        C2:D2:Stk2 -> {caught2,{C2,D2},Stk2=erlang:get_stacktrace()}
1117    end.
1118
1119stacktrace_2() ->
1120    ok = erlang:process_info(self(), current_function),
1121    ok.
1122
1123stacktrace_3(A, B) ->
1124    {ok,lists:prefix(A, B)}.
1125
1126nested_stacktrace(_Config) ->
1127    V = [{make_ref()}|[self()]],
1128    value1 = nested_stacktrace_1({{value,{V,x1}},void,{V,x1}},
1129                                 {void,void,void}),
1130    case ?MODULE:module_info(native) of
1131        false ->
1132            {caught1,
1133             [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
1134             value2} =
1135                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1136                                    {{value,{V,x2}},void,{V,x2}}),
1137            {caught1,
1138             [{erlang,'+',[V,x1],_},{?MODULE,my_add,2,_}|_],
1139             {caught2,[{erlang,abs,[V],_}|_]}} =
1140                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1141                                    {{'abs',V},error,badarg});
1142        true ->
1143            {caught1,
1144             [{?MODULE,my_add,2,_}|_],
1145             value2} =
1146                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1147                                    {{value,{V,x2}},void,{V,x2}}),
1148            {caught1,
1149             [{?MODULE,my_add,2,_}|_],
1150             {caught2,[{?MODULE,my_abs,1,_}|_]}} =
1151                nested_stacktrace_1({{'add',{V,x1}},error,badarith},
1152                                    {{'abs',V},error,badarg})
1153    end,
1154    ok.
1155
1156nested_stacktrace_1({X1,C1,V1}, {X2,C2,V2}) ->
1157    try foo(X1) of
1158        V1 -> value1
1159    catch
1160        C1:V1:S1 ->
1161            S1 = erlang:get_stacktrace(),
1162            T2 = try foo(X2) of
1163                     V2 -> value2
1164                 catch
1165                     C2:V2:S2 ->
1166                         S2 = erlang:get_stacktrace(),
1167                         {caught2,S2}
1168                 end,
1169            {caught1,S1,T2}
1170    end.
1171
1172raise(_Config) ->
1173    test_raise(fun() -> exit({exit,tuple}) end),
1174    test_raise(fun() -> abs(id(x)) end),
1175    test_raise(fun() -> throw({was,thrown}) end),
1176
1177    badarg = bad_raise(fun() -> abs(id(x)) end),
1178
1179    ok.
1180
1181bad_raise(Expr) ->
1182    try
1183        Expr()
1184    catch
1185        _:E:Stk ->
1186            erlang:raise(bad_class, E, Stk)
1187    end.
1188
1189test_raise(Expr) ->
1190    test_raise_1(Expr),
1191    test_raise_2(Expr),
1192    test_raise_3(Expr).
1193
1194test_raise_1(Expr) ->
1195    erase(exception),
1196    try
1197        do_test_raise_1(Expr)
1198    catch
1199        C:E:Stk ->
1200            {C,E,Stk} = erase(exception)
1201    end.
1202
1203do_test_raise_1(Expr) ->
1204    try
1205        Expr()
1206    catch
1207        C:E:Stk ->
1208            %% Here the stacktrace must be built.
1209            put(exception, {C,E,Stk}),
1210            erlang:raise(C, E, Stk)
1211    end.
1212
1213test_raise_2(Expr) ->
1214    erase(exception),
1215    try
1216        do_test_raise_2(Expr)
1217    catch
1218        C:E:Stk ->
1219            {C,E} = erase(exception),
1220            try
1221                Expr()
1222            catch
1223                _:_:S ->
1224                    [StkTop|_] = S,
1225                    [StkTop|_] = Stk
1226            end
1227    end.
1228
1229do_test_raise_2(Expr) ->
1230    try
1231        Expr()
1232    catch
1233        C:E:Stk ->
1234            %% Here it is possible to replace erlang:raise/3 with
1235            %% the raw_raise/3 instruction since the stacktrace is
1236            %% not actually used.
1237            put(exception, {C,E}),
1238            erlang:raise(C, E, Stk)
1239    end.
1240
1241test_raise_3(Expr) ->
1242    try
1243        do_test_raise_3(Expr)
1244    catch
1245        exit:{exception,C,E}:Stk ->
1246            try
1247                Expr()
1248            catch
1249                C:E:S ->
1250                    [StkTop|_] = S,
1251                    [StkTop|_] = Stk
1252            end
1253    end.
1254
1255do_test_raise_3(Expr) ->
1256    try
1257        Expr()
1258    catch
1259        C:E:Stk ->
1260            %% Here it is possible to replace erlang:raise/3 with
1261            %% the raw_raise/3 instruction since the stacktrace is
1262            %% not actually used.
1263            erlang:raise(exit, {exception,C,E}, Stk)
1264    end.
1265
1266
1267id(I) -> I.