diff options
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_type.erl | 1 | ||||
-rw-r--r-- | lib/compiler/src/beam_validator.erl | 1 | ||||
-rw-r--r-- | lib/compiler/src/erl_bifs.erl | 1 | ||||
-rw-r--r-- | lib/compiler/src/sys_core_fold.erl | 53 | ||||
-rw-r--r-- | lib/compiler/test/core_fold_SUITE.erl | 20 | ||||
-rw-r--r-- | lib/compiler/test/float_SUITE.erl | 7 | ||||
-rw-r--r-- | lib/compiler/test/guard_SUITE.erl | 13 | ||||
-rw-r--r-- | lib/compiler/test/warnings_SUITE.erl | 1 |
8 files changed, 71 insertions, 26 deletions
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index b4776294be..d324580cba 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -594,6 +594,7 @@ is_math_bif(atan2, 2) -> true; is_math_bif(pow, 2) -> true; is_math_bif(ceil, 1) -> true; is_math_bif(floor, 1) -> true; +is_math_bif(fmod, 2) -> true; is_math_bif(pi, 0) -> true; is_math_bif(_, _) -> false. diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index 6e53f53a20..5659077c5d 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -1646,6 +1646,7 @@ return_type_math(atan2, 2) -> {float,[]}; return_type_math(pow, 2) -> {float,[]}; return_type_math(ceil, 1) -> {float,[]}; return_type_math(floor, 1) -> {float,[]}; +return_type_math(fmod, 2) -> {float,[]}; return_type_math(pi, 0) -> {float,[]}; return_type_math(F, A) when is_atom(F), is_integer(A), A >= 0 -> term. diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl index 831730ba48..d60f73d421 100644 --- a/lib/compiler/src/erl_bifs.erl +++ b/lib/compiler/src/erl_bifs.erl @@ -138,6 +138,7 @@ is_pure(math, erf, 1) -> true; is_pure(math, erfc, 1) -> true; is_pure(math, exp, 1) -> true; is_pure(math, floor, 1) -> true; +is_pure(math, fmod, 2) -> true; is_pure(math, log, 1) -> true; is_pure(math, log2, 1) -> true; is_pure(math, log10, 1) -> true; diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index feb34b364f..5d7fd37270 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -172,13 +172,23 @@ guard(Expr, Sub) -> %% opt_guard_try(#c_seq{arg=Arg,body=Body0}=Seq) -> Body = opt_guard_try(Body0), - case {Arg,Body} of - {#c_call{module=#c_literal{val=Mod}, - name=#c_literal{val=Name}, - args=Args},#c_literal{val=false}} -> + WillFail = case Body of + #c_call{module=#c_literal{val=erlang}, + name=#c_literal{val=error}, + args=[_]} -> + true; + #c_literal{val=false} -> + true; + _ -> + false + end, + case Arg of + #c_call{module=#c_literal{val=Mod}, + name=#c_literal{val=Name}, + args=Args} when WillFail -> %% We have sequence consisting of a call (evaluated %% for a possible exception and/or side effect only), - %% followed by 'false'. + %% followed by 'false' or a call to error/1. %% 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 @@ -193,7 +203,7 @@ opt_guard_try(#c_seq{arg=Arg,body=Body0}=Seq) -> %% be safely removed. Body end; - {_,_} -> + _ -> Seq#c_seq{body=Body} end; opt_guard_try(#c_case{clauses=Cs}=Term) -> @@ -1142,7 +1152,13 @@ clause_1(#c_clause{guard=G0,body=B0}=Cl, Ps1, Cexpr, Ctxt, Sub1) -> %% %% case A of NewVar when true -> ... %% - sub_set_var(Var, Cexpr, Sub2); + case cerl:is_c_fname(Cexpr) of + false -> + sub_set_var(Var, Cexpr, Sub2); + true -> + %% We must not copy funs, and especially not into guards. + Sub2 + end; _ -> Sub2 end, @@ -2135,7 +2151,7 @@ letify(Bs, Body) -> -spec opt_not_in_let(cerl:c_let()) -> cerl:cerl(). opt_not_in_let(#c_let{vars=[_]=Vs0,arg=Arg0,body=Body0}=Let) -> - case opt_not_in_let(Vs0, Arg0, Body0) of + case opt_not_in_let_0(Vs0, Arg0, Body0) of {[],#c_values{es=[]},Body} -> Body; {Vs,Arg,Body} -> @@ -2143,13 +2159,7 @@ opt_not_in_let(#c_let{vars=[_]=Vs0,arg=Arg0,body=Body0}=Let) -> end; opt_not_in_let(Let) -> Let. -%% opt_not_in_let(Vs, Arg, Body) -> {Vs',Arg',Body'} -%% Try to optimize away a 'not' operator in a 'let'. - --spec opt_not_in_let([cerl:c_var()], cerl:cerl(), cerl:cerl()) -> - {[cerl:c_var()],cerl:cerl(),cerl:cerl()}. - -opt_not_in_let([#c_var{name=V}]=Vs0, Arg0, Body0) -> +opt_not_in_let_0([#c_var{name=V}]=Vs0, Arg0, Body0) -> case cerl:type(Body0) of call -> %% let <V> = Expr in not V ==> @@ -2180,9 +2190,7 @@ opt_not_in_let([#c_var{name=V}]=Vs0, Arg0, Body0) -> end; _ -> {Vs0,Arg0,Body0} - end; -opt_not_in_let(Vs, Arg, Body) -> - {Vs,Arg,Body}. + end. opt_not_in_let_1(V, Call, Body) -> case Call of @@ -2636,11 +2644,10 @@ opt_simple_let_0(#c_let{arg=Arg0}=Let, Ctxt, Sub) -> opt_simple_let_1(#c_let{vars=Vs0,body=B0}=Let, Arg0, Ctxt, Sub0) -> %% Optimise let and add new substitutions. - {Vs1,Args,Sub1} = let_substs(Vs0, Arg0, Sub0), - BodySub = update_let_types(Vs1, Args, Sub1), - B1 = body(B0, Ctxt, BodySub), - Arg1 = core_lib:make_values(Args), - {Vs,Arg,B} = opt_not_in_let(Vs1, Arg1, B1), + {Vs,Args,Sub1} = let_substs(Vs0, Arg0, Sub0), + BodySub = update_let_types(Vs, Args, Sub1), + B = body(B0, Ctxt, BodySub), + Arg = core_lib:make_values(Args), opt_simple_let_2(Let, Vs, Arg, B, B0, Ctxt, Sub1). opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Ctxt, Sub) -> diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index ced0e39d06..0097e28d4d 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -26,7 +26,7 @@ unused_multiple_values_error/1,unused_multiple_values/1, multiple_aliases/1,redundant_boolean_clauses/1, mixed_matching_clauses/1,unnecessary_building/1, - no_no_file/1,configuration/1]). + no_no_file/1,configuration/1,supplies/1]). -export([foo/0,foo/1,foo/2,foo/3]). @@ -45,7 +45,7 @@ groups() -> unused_multiple_values_error,unused_multiple_values, multiple_aliases,redundant_boolean_clauses, mixed_matching_clauses,unnecessary_building, - no_no_file,configuration]}]. + no_no_file,configuration,supplies]}]. init_per_suite(Config) -> @@ -511,4 +511,20 @@ configuration() -> art() -> creating. +%% core_lint would complain after optimization. A call to error/1 +%% must not occur unconditionally in a guard. +supplies(_Config) -> + case ?MODULE of + core_fold_inline_SUITE -> + %% Other error behaviour when inlined. + ok; + _ -> + {'EXIT',{function_clause,_}} = (catch do_supplies(#{1 => <<1,2,3>>})), + {'EXIT',{function_clause,_}} = (catch do_supplies(#{1 => a})), + {'EXIT',{function_clause,_}} = (catch do_supplies(42)), + ok + end. + +do_supplies(#{1 := Value}) when byte_size(Value), byte_size(kg) -> working. + id(I) -> I. diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl index 0ebc71eb9b..08c3dd8593 100644 --- a/lib/compiler/test/float_SUITE.erl +++ b/lib/compiler/test/float_SUITE.erl @@ -155,6 +155,13 @@ math_functions(Config) when is_list(Config) -> 5.0 = math:floor(id(5.4)), 6.0 = math:ceil(id(5.4)), + 0.0 = math:fmod(42, 42), + 0.25 = math:fmod(1, 0.75), + -1.0 = math:fmod(-4.0, 1.5), + -0.375 = math:fmod(-3.0, -0.875), + 0.125 = math:fmod(8.125, -4), + {'EXIT',{badarith,_}} = (catch math:fmod(5.0, 0.0)), + %% Only for coverage (of beam_type.erl). {'EXIT',{undef,_}} = (catch math:fnurfla(0)), {'EXIT',{undef,_}} = (catch math:fnurfla(0, 0)), diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index 6302f82f29..429d6b79e0 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -87,6 +87,7 @@ misc(Config) when is_list(Config) -> {ok,buf,<<>>} = get_data({o,true,0}, 42, buf), {ok,buf,<<>>} = get_data({o,false,0}, 0, buf), error = get_data({o,false,0}, 42, buf), + ok. @@ -343,6 +344,11 @@ complex_semicolon(Config) when is_list(Config) -> ok = csemi7(#{a=>1}, 3, 3), ok = csemi7(#{a=>1, b=>3}, 0, 0), + %% 8: Make sure that funs cannot be copied into guards. + ok = csemi8(true), + error = csemi8(false), + error = csemi8(42), + ok. csemi1(Type, Val) when is_list(Val), Type == float; @@ -457,6 +463,13 @@ csemi6(_, _) -> error. csemi7(A, B, C) when A#{a:=B} > #{a=>1}; abs(C) > 2 -> ok; csemi7(_, _, _) -> error. +csemi8(Together) -> + case fun csemi8/1 of + Typically when Together; Typically, Together -> ok; + _ -> error + end. + + comma(Config) when is_list(Config) -> %% ',' combinations of literal true/false. diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index f884e6e7d6..35f7db82bd 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -281,7 +281,6 @@ bad_arith(Config) when is_list(Config) -> {3,sys_core_fold,{eval_failure,badarith}}, {9,sys_core_fold,nomatch_guard}, {9,sys_core_fold,{eval_failure,badarith}}, - {9,sys_core_fold,{no_effect,{erlang,is_integer,1}}}, {10,sys_core_fold,nomatch_guard}, {10,sys_core_fold,{eval_failure,badarith}}, {15,sys_core_fold,{eval_failure,badarith}} |