PageRenderTime 338ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/compiler/test/trycatch_SUITE.erl

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