PageRenderTime 108ms CodeModel.GetById 2ms app.highlight 97ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/compiler/test/trycatch_SUITE.erl

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