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