aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/sys_core_fold.erl24
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl21
2 files changed, 37 insertions, 8 deletions
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 620b4e8847..c92ee86e07 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -150,14 +150,26 @@ guard(Expr, Sub) ->
opt_guard_try(#c_seq{arg=Arg,body=Body0}=Seq) ->
Body = opt_guard_try(Body0),
case {Arg,Body} of
- {#c_call{},#c_literal{val=false}} ->
- %% We have sequence consisting of a call (evaluted
- %% for a possible exception only), followed by 'false'.
- %% Since the sequence is inside a try block that will
+ {#c_call{module=#c_literal{val=Mod},
+ name=#c_literal{val=Name},
+ args=Args},#c_literal{val=false}} ->
+ %% We have sequence consisting of a call (evaluated
+ %% for a possible exception and/or side effect only),
+ %% followed by 'false'.
+ %% Since the sequence is inside a try block that will
%% default to 'false' if any exception occurs, not
%% evalutating the call will not change the behaviour
- %% of the guard.
- Body;
+ %% provided that the call has no side effects.
+ case erl_bifs:is_pure(Mod, Name, length(Args)) of
+ false ->
+ %% Not a pure BIF (meaning that this is not
+ %% a guard and that we must keep the call).
+ Seq#c_seq{body=Body};
+ true ->
+ %% The BIF has no side effects, so it can
+ %% be safely removed.
+ Body
+ end;
{_,_} ->
Seq#c_seq{body=Body}
end;
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index fb5ec88c9f..54bd52947e 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -21,7 +21,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1,
- eq/1,nested_call_in_case/1,coverage/1]).
+ eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -32,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
[t_element, setelement, t_length, append, t_apply, bifs,
- eq, nested_call_in_case, coverage].
+ eq, nested_call_in_case, guard_try_catch, coverage].
groups() ->
[].
@@ -207,6 +207,23 @@ nested_call_in_case(Config) when is_list(Config) ->
?line {'EXIT',_} = (catch Mod:a(not_a_list, 42)),
ok.
+guard_try_catch(_Config) ->
+ false = do_guard_try_catch(key, value),
+ value = get(key),
+ ok.
+
+do_guard_try_catch(K, V) ->
+ %% This try...catch block looks like a guard.
+ %% Make sure that it is not optimized like a guard
+ %% (the put/2 call must not be optimized away).
+ try
+ put(K, V),
+ false
+ catch
+ _:_ ->
+ false
+ end.
+
coverage(Config) when is_list(Config) ->
?line {'EXIT',{{case_clause,{a,b,c}},_}} =
(catch cover_will_match_list_type({a,b,c})),