PageRenderTime 56ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/compiler/test/trycatch_SUITE.erl

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