/lib/compiler/test/trycatch_SUITE.erl
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.