diff options
Diffstat (limited to 'lib/compiler')
| -rw-r--r-- | lib/compiler/doc/src/notes.xml | 174 | ||||
| -rw-r--r-- | lib/compiler/src/Makefile | 3 | ||||
| -rw-r--r-- | lib/compiler/src/compile.erl | 11 | ||||
| -rw-r--r-- | lib/compiler/src/compiler.app.src | 3 | ||||
| -rwxr-xr-x | lib/compiler/src/genop.tab | 2 | ||||
| -rw-r--r-- | lib/compiler/src/sys_core_bsm.erl | 355 | ||||
| -rw-r--r-- | lib/compiler/src/sys_core_fold.erl | 320 | ||||
| -rw-r--r-- | lib/compiler/src/v3_kernel.erl | 27 | ||||
| -rw-r--r-- | lib/compiler/src/v3_kernel_pp.erl | 2 | ||||
| -rw-r--r-- | lib/compiler/test/beam_type_SUITE.erl | 25 | ||||
| -rw-r--r-- | lib/compiler/test/beam_validator_SUITE.erl | 2 | ||||
| -rw-r--r-- | lib/compiler/test/bs_construct_SUITE.erl | 2 | ||||
| -rw-r--r-- | lib/compiler/test/bs_match_SUITE.erl | 21 | ||||
| -rw-r--r-- | lib/compiler/test/compile_SUITE.erl | 1 | ||||
| -rw-r--r-- | lib/compiler/test/core_SUITE.erl | 8 | ||||
| -rw-r--r-- | lib/compiler/test/core_SUITE_data/non_variable_apply.core | 80 | ||||
| -rw-r--r-- | lib/compiler/test/misc_SUITE.erl | 3 | ||||
| -rw-r--r-- | lib/compiler/test/warnings_SUITE.erl | 4 | ||||
| -rw-r--r-- | lib/compiler/vsn.mk | 2 |
19 files changed, 714 insertions, 331 deletions
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index 1dc0c808e7..f3d42a909b 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -32,6 +32,180 @@ <p>This document describes the changes made to the Compiler application.</p> +<section><title>Compiler 7.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>For many releases, it has been legal to override a BIF + with a local function having the same name. However, + calling a local function with the same name as guard BIF + as filter in a list comprehension was not allowed.</p> + <p> + Own Id: OTP-13690</p> + </item> + <item> + <p>compile:forms/2 would not return the module name as + documented when one of the options '<c>from_core</c>', + '<c>from_asm</c>', or '<c>from_beam</c>' was given. Also, + the compiler would crash if one of those options was + combined with '<c>native</c>'.</p> + <p> + Own Id: OTP-14408 Aux Id: ERL-417 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Optimized test for tuples with an atom as first element.</p> + <p> + Own Id: OTP-12148</p> + </item> + <item> + <p> + Compilation of modules with huge literal binary strings + is now much faster.</p> + <p> + Own Id: OTP-13794</p> + </item> + <item> + <p>Replaced usage of deprecated symbolic <seealso + marker="erts:erlang#type-time_unit"><c>time + unit</c></seealso> representations.</p> + <p> + Own Id: OTP-13831 Aux Id: OTP-13735 </p> + </item> + <item> + <p>The undocumented and unsupported module + <c>sys_pre_expand</c> has been removed. As a partial + replacement for the functionality, there is a new + function <c>erl_internal:add_predefined_functions/1</c> + and <c>erl_expand_records</c> will now add a module + prefix to calls to BIFs and imported functions.</p> + <p> + Own Id: OTP-13856</p> + </item> + <item> + <p>The internal compiler passes now start all generated + variables with "@" to avoid any conflicts with variables + in languages such as Elixir or LFE.</p> + <p> + Own Id: OTP-13924</p> + </item> + <item> + <p>The function <c>fmod/2</c> has been added to the + <c>math</c> module.</p> + <p> + Own Id: OTP-14000</p> + </item> + <item> + <p>Code generation for complicated guards have been + improved.</p> + <p> + Own Id: OTP-14042</p> + </item> + <item> + <p> + The compiler has new warnings for repeated identical map + keys.</p> + <p> + A map expression such as,</p> + <p> + <c> #{'a' => 1, 'b' => 2, 'a' => 3}.</c></p> + <p> + will produce a warning for the repeated key 'a'.</p> + <p> + Own Id: OTP-14058</p> + </item> + <item> + <p>By default, there will now be a warning when + <c>export_all</c> is used. The warning can be disabled + using <c>nowarn_export_all</c>.</p> + <p> + Own Id: OTP-14071</p> + </item> + <item> + <p> + Optimize maps pattern matching by only examining the + common keys in each clause first instead of all keys. + This will reduce the number of lookups of each key in + maps pattern matching.</p> + <p> + Own Id: OTP-14072</p> + </item> + <item> + <p>There is a new '<c>deterministic</c>' option to omit + '<c>source</c>' and '<c>options</c>' tuples in the BEAM + file.</p> + <p> + Own Id: OTP-14087</p> + </item> + <item> + <p> + Analyzing modules with binary construction with huge + strings is now much faster. The compiler also compiles + such modules slightly faster.</p> + <p> + Own Id: OTP-14125 Aux Id: ERL-308 </p> + </item> + <item> + <p>Atoms may now contain arbitrary Unicode + characters.</p> + <p> + Own Id: OTP-14178</p> + </item> + <item> + <p><c>compile:file/2</c> now accepts the option + <c>extra_chunks</c> to include extra chunks in the BEAM + file.</p> + <p> + Own Id: OTP-14221</p> + </item> + <item> + <p>The format of debug information that is stored in BEAM + files (when <c>debug_info</c> is used) has been changed. + The purpose of the change is to better support other + BEAM-based languages such as Elixir or LFE.</p> + <p>All tools included in OTP (dialyzer, debugger, cover, + and so on) will handle both the new format and the + previous format. Tools that retrieve the debug + information using <c>beam_lib:chunk(Beam, + [abstract_code])</c> will continue to work with both the + new and old format. Tools that call + <c>beam_lib:chunk(Beam, ["Abst"])</c> will not work with + the new format.</p> + <p>For more information, see the description of + <c>debug_info</c> in the documentation for + <c>beam_lib</c> and the description of the + <c>{debug_info,{Backend,Data}}</c> option in the + documentation for <c>compile</c>.</p> + <p> + Own Id: OTP-14369 Aux Id: PR-1367 </p> + </item> + <item> + <p>In a future release, <c>erlang:get_stacktrace/0</c> + will probably only work when called from within a + '<c>try</c>' expression (otherwise it will return + <c>[]</c>.</p> + <p>To help prepare for that change, the compiler will now + by default warn if '<c>get_stacktrace/0</c>' is used in a + way that will not work in the future. Note that the + warning will not be issued if '<c>get_stacktrace/0</c>' + is used in a function that uses neither '<c>catch</c>' + nor '<c>try</c>' (because that could be a legal use if + the function is called from within a '<c>try</c>'.</p> + <p> + Own Id: OTP-14401</p> + </item> + </list> + </section> + +</section> + <section><title>Compiler 7.0.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile index 59b80ade5d..ef6db66ff6 100644 --- a/lib/compiler/src/Makefile +++ b/lib/compiler/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2016. All Rights Reserved. +# Copyright Ericsson AB 1996-2017. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -83,6 +83,7 @@ MODULES = \ core_scan \ erl_bifs \ rec_env \ + sys_core_bsm \ sys_core_dsetel \ sys_core_fold \ sys_core_fold_lists \ diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index c6e61d543e..aa2d224bb4 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -264,9 +264,9 @@ format_error({delete_temp,File,Error}) -> io_lib:format("failed to delete temporary file ~ts: ~ts", [File,file:format_error(Error)]); format_error({parse_transform,M,R}) -> - io_lib:format("error in parse transform '~s': ~tp", [M, R]); + io_lib:format("error in parse transform '~ts': ~tp", [M, R]); format_error({undef_parse_transform,M}) -> - io_lib:format("undefined parse transform '~s'", [M]); + io_lib:format("undefined parse transform '~ts'", [M]); format_error({core_transform,M,R}) -> io_lib:format("error in core transform '~s': ~tp", [M, R]); format_error({crash,Pass,Reason}) -> @@ -718,8 +718,10 @@ core_passes() -> | kernel_passes()]. kernel_passes() -> - %% Destructive setelement/3 optimization and core lint. - [{pass,sys_core_dsetel}, + %% Optimizations that must be done after all other optimizations. + [{pass,sys_core_bsm}, + {iff,dcbsm,{listing,"core_bsm"}}, + {pass,sys_core_dsetel}, {iff,dsetel,{listing,"dsetel"}}, {iff,clint,?pass(core_lint_module)}, @@ -1919,6 +1921,7 @@ pre_load() -> erl_lint, erl_parse, erl_scan, + sys_core_bsm, sys_core_dsetel, sys_core_fold, v3_codegen, diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src index 3961b2af86..3139d68902 100644 --- a/lib/compiler/src/compiler.app.src +++ b/lib/compiler/src/compiler.app.src @@ -1,7 +1,7 @@ % This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2016. All Rights Reserved. +%% Copyright Ericsson AB 1997-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -58,6 +58,7 @@ core_lib, erl_bifs, rec_env, + sys_core_bsm, sys_core_dsetel, sys_core_fold, sys_core_fold_lists, diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab index 9efb9ad6f8..b5688de339 100755 --- a/lib/compiler/src/genop.tab +++ b/lib/compiler/src/genop.tab @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2016. All Rights Reserved. +# Copyright Ericsson AB 1998-2017. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/lib/compiler/src/sys_core_bsm.erl b/lib/compiler/src/sys_core_bsm.erl new file mode 100644 index 0000000000..3e04cc33df --- /dev/null +++ b/lib/compiler/src/sys_core_bsm.erl @@ -0,0 +1,355 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +%% Purpose : Optimize bit syntax matching. + + +-module(sys_core_bsm). +-export([module/2,format_error/1]). + +-include("core_parse.hrl"). +-import(lists, [member/2,nth/2,reverse/1,usort/1]). + +-spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}. + +module(#c_module{defs=Ds0}=Mod, Opts) -> + {Ds,Ws0} = function(Ds0, [], []), + case member(bin_opt_info, Opts) of + false -> + {ok,Mod#c_module{defs=Ds}}; + true -> + Ws1 = [make_warning(Where, What) || {Where,What} <- Ws0], + Ws = usort(Ws1), + {ok,Mod#c_module{defs=Ds},Ws} + end. + +function([{#c_var{name={F,Arity}}=Name,B0}|Fs], FsAcc, Ws0) -> + try cerl_trees:mapfold(fun bsm_an/2, Ws0, B0) of + {B,Ws} -> + function(Fs, [{Name,B}|FsAcc], Ws) + catch + Class:Error -> + Stack = erlang:get_stacktrace(), + io:fwrite("Function: ~w/~w\n", [F,Arity]), + erlang:raise(Class, Error, Stack) + end; +function([], Fs, Ws) -> + {reverse(Fs),Ws}. + +-type error() :: atom(). +-spec format_error(error()) -> nonempty_string(). + +format_error(bin_opt_alias) -> + "INFO: the '=' operator will prevent delayed sub binary optimization"; +format_error(bin_partition) -> + "INFO: matching non-variables after a previous clause matching a variable " + "will prevent delayed sub binary optimization"; +format_error(bin_left_var_used_in_guard) -> + "INFO: a variable to the left of the binary pattern is used in a guard; " + "will prevent delayed sub binary optimization"; +format_error(bin_argument_order) -> + "INFO: matching anything else but a plain variable to the left of " + "binary pattern will prevent delayed sub binary optimization; " + "SUGGEST changing argument order"; +format_error(bin_var_used) -> + "INFO: using a matched out sub binary will prevent " + "delayed sub binary optimization"; +format_error(orig_bin_var_used_in_guard) -> + "INFO: using the original binary variable in a guard will prevent " + "delayed sub binary optimization"; +format_error(bin_var_used_in_guard) -> + "INFO: using a matched out sub binary in a guard will prevent " + "delayed sub binary optimization". + + +%%% +%%% Annotate bit syntax matching to faciliate optimization in further passes. +%%% + +bsm_an(Core0, Ws0) -> + case bsm_an(Core0) of + {ok,Core} -> + {Core,Ws0}; + {ok,Core,W} -> + {Core,[W|Ws0]} + end. + +bsm_an(#c_case{arg=#c_var{}=V}=Case) -> + bsm_an_1([V], Case); +bsm_an(#c_case{arg=#c_values{es=Es}}=Case) -> + bsm_an_1(Es, Case); +bsm_an(Other) -> + {ok,Other}. + +bsm_an_1(Vs, #c_case{clauses=Cs}=Case) -> + case bsm_leftmost(Cs) of + none -> {ok,Case}; + Pos -> bsm_an_2(Vs, Cs, Case, Pos) + end. + +bsm_an_2(Vs, Cs, Case, Pos) -> + case bsm_nonempty(Cs, Pos) of + true -> bsm_an_3(Vs, Cs, Case, Pos); + false -> {ok,Case} + end. + +bsm_an_3(Vs, Cs, Case, Pos) -> + try + bsm_ensure_no_partition(Cs, Pos), + {ok,bsm_do_an(Vs, Pos, Cs, Case)} + catch + throw:{problem,Where,What} -> + {ok,Case,{Where,What}} + end. + +bsm_do_an(Vs0, Pos, Cs0, Case) -> + case nth(Pos, Vs0) of + #c_var{name=Vname}=V0 -> + Cs = bsm_do_an_var(Vname, Pos, Cs0, []), + V = bsm_annotate_for_reuse(V0), + Bef = lists:sublist(Vs0, Pos-1), + Aft = lists:nthtail(Pos, Vs0), + case Bef ++ [V|Aft] of + [_] -> + Case#c_case{arg=V,clauses=Cs}; + Vs -> + Case#c_case{arg=#c_values{es=Vs},clauses=Cs} + end; + _ -> + Case + end. + +bsm_do_an_var(V, S, [#c_clause{pats=Ps,guard=G,body=B0}=C0|Cs], Acc) -> + case nth(S, Ps) of + #c_var{name=VarName} -> + case core_lib:is_var_used(V, G) of + true -> bsm_problem(C0, orig_bin_var_used_in_guard); + false -> ok + end, + case core_lib:is_var_used(VarName, G) of + true -> bsm_problem(C0, bin_var_used_in_guard); + false -> ok + end, + B1 = bsm_maybe_ctx_to_binary(VarName, B0), + B = bsm_maybe_ctx_to_binary(V, B1), + C = C0#c_clause{body=B}, + bsm_do_an_var(V, S, Cs, [C|Acc]); + #c_alias{}=P -> + case bsm_could_match_binary(P) of + false -> + bsm_do_an_var(V, S, Cs, [C0|Acc]); + true -> + bsm_problem(C0, bin_opt_alias) + end; + P -> + case bsm_could_match_binary(P) andalso bsm_is_var_used(V, G, B0) of + false -> + bsm_do_an_var(V, S, Cs, [C0|Acc]); + true -> + bsm_problem(C0, bin_var_used) + end + end; +bsm_do_an_var(_, _, [], Acc) -> reverse(Acc). + +bsm_annotate_for_reuse(#c_var{anno=Anno}=Var) -> + Var#c_var{anno=[reuse_for_context|Anno]}. + +bsm_is_var_used(V, G, B) -> + core_lib:is_var_used(V, G) orelse core_lib:is_var_used(V, B). + +bsm_maybe_ctx_to_binary(V, B) -> + case core_lib:is_var_used(V, B) andalso not previous_ctx_to_binary(V, B) of + false -> + B; + true -> + #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary}, + args=[#c_var{name=V}]}, + body=B} + end. + +previous_ctx_to_binary(V, Core) -> + case Core of + #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary}, + args=[#c_var{name=V}]}} -> + true; + _ -> + false + end. + +%% bsm_leftmost(Cs) -> none | ArgumentNumber +%% Find the leftmost argument that does binary matching. Return +%% the number of the argument (1-N). + +bsm_leftmost(Cs) -> + bsm_leftmost_1(Cs, none). + +bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) -> + bsm_leftmost_2(Ps, Cs, 1, Pos); +bsm_leftmost_1([], Pos) -> Pos. + +bsm_leftmost_2(_, Cs, Pos, Pos) -> + bsm_leftmost_1(Cs, Pos); +bsm_leftmost_2([#c_binary{}|_], Cs, N, _) -> + bsm_leftmost_1(Cs, N); +bsm_leftmost_2([_|Ps], Cs, N, Pos) -> + bsm_leftmost_2(Ps, Cs, N+1, Pos); +bsm_leftmost_2([], Cs, _, Pos) -> + bsm_leftmost_1(Cs, Pos). + +%% bsm_nonempty(Cs, Pos) -> true|false +%% Check if at least one of the clauses matches a non-empty +%% binary in the given argument position. +%% +bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) -> + case nth(Pos, Ps) of + #c_binary{segments=[_|_]} -> + true; + _ -> + bsm_nonempty(Cs, Pos) + end; +bsm_nonempty([], _ ) -> false. + +%% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem) +%% We must make sure that matching is not partitioned between +%% variables like this: +%% foo(<<...>>) -> ... +%% foo(<Variable>) when ... -> ... +%% foo(<Any non-variable pattern>) -> +%% If there is such partition, we are not allowed to reuse the binary variable +%% for the match context. +%% +%% Also, arguments to the left of the argument that is matched +%% against a binary, are only allowed to be simple variables, not +%% used in guards. The reason is that we must know that the binary is +%% only matched in one place (i.e. there must be only one bs_start_match2 +%% instruction emitted). + +bsm_ensure_no_partition(Cs, Pos) -> + bsm_ensure_no_partition_1(Cs, Pos, before). + +%% Loop through each clause. +bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) -> + State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0), + case State of + 'after' -> + bsm_ensure_no_partition_after(Cs, Pos); + _ -> + ok + end, + bsm_ensure_no_partition_1(Cs, Pos, State); +bsm_ensure_no_partition_1([], _, _) -> ok. + +%% Loop through each pattern for this clause. +bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) -> + case State of + before when Vstate =:= simple_vars -> within; + before -> bsm_problem(Where, Vstate); + within when Vstate =:= simple_vars -> within; + within -> bsm_problem(Where, Vstate) + end; +bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) -> + %% Retrieve the real pattern that the alias refers to and check that. + P = bsm_real_pattern(Alias), + bsm_ensure_no_partition_2([P], 1, N, Vstate, State); +bsm_ensure_no_partition_2([_|_], 1, _, _Vstate, before=State) -> + %% No binary matching yet - therefore no partition. + State; +bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) -> + case bsm_could_match_binary(P) of + false -> + %% If clauses can be freely arranged (Vstate =:= simple_vars), + %% a clause that cannot match a binary will not partition the clause. + %% Example: + %% + %% a(Var, <<>>) -> ... + %% a(Var, []) -> ... + %% a(Var, <<B>>) -> ... + %% + %% But if the clauses can't be freely rearranged, as in + %% + %% b(Var, <<X>>) -> ... + %% b(1, 2) -> ... + %% + %% we do have a problem. + %% + case Vstate of + simple_vars -> State; + _ -> bsm_problem(P, Vstate) + end; + true -> + %% The pattern P *may* match a binary, so we must update the state. + %% (P must be a variable.) + case State of + within -> 'after'; + 'after' -> 'after' + end + end; +bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) -> + case core_lib:is_var_used(V, G) of + false -> + bsm_ensure_no_partition_2(Ps, N-1, G, Vstate, S); + true -> + bsm_ensure_no_partition_2(Ps, N-1, G, bin_left_var_used_in_guard, S) + end; +bsm_ensure_no_partition_2([_|Ps], N, G, _, S) -> + bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S). + +bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs], Pos) -> + case nth(Pos, Ps) of + #c_var{} -> + bsm_ensure_no_partition_after(Cs, Pos); + _ -> + bsm_problem(C, bin_partition) + end; +bsm_ensure_no_partition_after([], _) -> ok. + +bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P); +bsm_could_match_binary(#c_cons{}) -> false; +bsm_could_match_binary(#c_tuple{}) -> false; +bsm_could_match_binary(#c_literal{val=Lit}) -> is_bitstring(Lit); +bsm_could_match_binary(_) -> true. + +bsm_real_pattern(#c_alias{pat=P}) -> bsm_real_pattern(P); +bsm_real_pattern(P) -> P. + +bsm_problem(Where, What) -> + throw({problem,Where,What}). + +make_warning(Core, Term) -> + case should_suppress_warning(Core) of + true -> + ok; + false -> + Anno = cerl:get_ann(Core), + Line = get_line(Anno), + File = get_file(Anno), + {File,[{Line,?MODULE,Term}]} + end. + +should_suppress_warning(Core) -> + Ann = cerl:get_ann(Core), + member(compiler_generated, Ann). + +get_line([Line|_]) when is_integer(Line) -> Line; +get_line([_|T]) -> get_line(T); +get_line([]) -> none. + +get_file([{file,File}|_]) -> File; +get_file([_|T]) -> get_file(T); +get_file([]) -> "no_file". % should not happen diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 3673a339f6..d73060fb7e 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -71,7 +71,7 @@ -export([module/2,format_error/1]). -import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,all/2,any/2, - reverse/1,reverse/2,member/2,nth/2,flatten/1, + reverse/1,reverse/2,member/2,flatten/1, unzip/1,keyfind/3]). -import(cerl, [ann_c_cons/3,ann_c_map/3,ann_c_tuple/2]). @@ -107,7 +107,6 @@ {'ok', cerl:c_module(), [_]}. module(#c_module{defs=Ds0}=Mod, Opts) -> - put(bin_opt_info, member(bin_opt_info, Opts)), put(no_inline_list_funcs, not member(inline_list_funcs, Opts)), case get(new_var_num) of undefined -> put(new_var_num, 0); @@ -116,7 +115,6 @@ module(#c_module{defs=Ds0}=Mod, Opts) -> init_warnings(), Ds1 = [function_1(D) || D <- Ds0], erase(no_inline_list_funcs), - erase(bin_opt_info), {ok,Mod#c_module{defs=Ds1},get_warnings()}. function_1({#c_var{name={F,Arity}}=Name,B0}) -> @@ -383,10 +381,8 @@ expr(#c_case{}=Case0, Ctxt, Sub) -> warn_no_clause_match(Case1, Case), Expr = eval_case(Case, Sub), case move_case_into_arg(Case, Sub) of - impossible -> - bsm_an(Expr); - Other -> - Other + impossible -> Expr; + Other -> Other end; Other -> expr(Other, Ctxt, Sub) @@ -399,10 +395,10 @@ expr(#c_receive{clauses=Cs0,timeout=T0,action=A0}=Recv, Ctxt, Sub) -> expr(#c_apply{anno=Anno,op=Op0,args=As0}=App, _, Sub) -> Op1 = expr(Op0, value, Sub), As1 = expr_list(As0, value, Sub), - case Op1 of - #c_var{} -> + case cerl:is_data(Op1) of + false -> App#c_apply{op=Op1,args=As1}; - _ -> + true -> add_warning(App, invalid_call), Err = #c_call{anno=Anno, module=#c_literal{val=erlang}, @@ -1462,8 +1458,19 @@ sub_add_scope(Vs, #sub{s=Scope0}=Sub) -> Sub#sub{s=Scope}. sub_subst_scope(#sub{v=S0,s=Scope}=Sub) -> - S = [{-1,#c_var{name=Sv}} || Sv <- cerl_sets:to_list(Scope)]++S0, - Sub#sub{v=S}. + Initial = case S0 of + [{NegInt,_}|_] when is_integer(NegInt), NegInt < 0 -> + NegInt - 1; + _ -> + -1 + end, + S = sub_subst_scope_1(cerl_sets:to_list(Scope), Initial, S0), + Sub#sub{v=orddict:from_list(S)}. + +%% The keys in an orddict must be unique. Make them so! +sub_subst_scope_1([H|T], Key, Acc) -> + sub_subst_scope_1(T, Key-1, [{Key,#c_var{name=H}}|Acc]); +sub_subst_scope_1([], _, Acc) -> Acc. sub_is_val(#c_var{name=V}, #sub{v=S,s=Scope}) -> %% When the bottleneck in sub_del_var/2 was eliminated, this @@ -2943,15 +2950,8 @@ update_types(Expr, Pat, #sub{t=Tdb0}=Sub) -> Tdb = update_types_1(Expr, Pat, Tdb0), Sub#sub{t=Tdb}. -update_types_1(#c_var{name=V,anno=Anno}, Pat, Types) -> - case member(reuse_for_context, Anno) of - true -> - %% If a variable has been marked for reuse of binary context, - %% optimizations based on type information are unsafe. - kill_types(V, Types); - false -> - update_types_2(V, Pat, Types) - end; +update_types_1(#c_var{name=V}, Pat, Types) -> + update_types_2(V, Pat, Types); update_types_1(_, _, Types) -> Types. update_types_2(V, [#c_tuple{}=P], Types) -> @@ -2994,253 +2994,6 @@ copy_type(_, _, Tdb) -> Tdb. void() -> #c_literal{val=ok}. -%%% -%%% Annotate bit syntax matching to faciliate optimization in further passes. -%%% - -bsm_an(#c_case{arg=#c_var{}=V}=Case) -> - bsm_an_1([V], Case); -bsm_an(#c_case{arg=#c_values{es=Es}}=Case) -> - bsm_an_1(Es, Case); -bsm_an(Other) -> Other. - -bsm_an_1(Vs, #c_case{clauses=Cs}=Case) -> - case bsm_leftmost(Cs) of - none -> Case; - Pos -> bsm_an_2(Vs, Cs, Case, Pos) - end. - -bsm_an_2(Vs, Cs, Case, Pos) -> - case bsm_nonempty(Cs, Pos) of - true -> bsm_an_3(Vs, Cs, Case, Pos); - false -> Case - end. - -bsm_an_3(Vs, Cs, Case, Pos) -> - try - bsm_ensure_no_partition(Cs, Pos), - bsm_do_an(Vs, Pos, Cs, Case) - catch - throw:{problem,Where,What} -> - add_bin_opt_info(Where, What), - Case - end. - -bsm_do_an(Vs0, Pos, Cs0, Case) -> - case nth(Pos, Vs0) of - #c_var{name=Vname}=V0 -> - Cs = bsm_do_an_var(Vname, Pos, Cs0, []), - V = bsm_annotate_for_reuse(V0), - Bef = lists:sublist(Vs0, Pos-1), - Aft = lists:nthtail(Pos, Vs0), - case Bef ++ [V|Aft] of - [_] -> - Case#c_case{arg=V,clauses=Cs}; - Vs -> - Case#c_case{arg=#c_values{es=Vs},clauses=Cs} - end; - _ -> - Case - end. - -bsm_do_an_var(V, S, [#c_clause{pats=Ps,guard=G,body=B0}=C0|Cs], Acc) -> - case nth(S, Ps) of - #c_var{name=VarName} -> - case core_lib:is_var_used(V, G) of - true -> bsm_problem(C0, orig_bin_var_used_in_guard); - false -> ok - end, - case core_lib:is_var_used(VarName, G) of - true -> bsm_problem(C0, bin_var_used_in_guard); - false -> ok - end, - B1 = bsm_maybe_ctx_to_binary(VarName, B0), - B = bsm_maybe_ctx_to_binary(V, B1), - C = C0#c_clause{body=B}, - bsm_do_an_var(V, S, Cs, [C|Acc]); - #c_alias{}=P -> - case bsm_could_match_binary(P) of - false -> - bsm_do_an_var(V, S, Cs, [C0|Acc]); - true -> - bsm_problem(C0, bin_opt_alias) - end; - P -> - case bsm_could_match_binary(P) andalso bsm_is_var_used(V, G, B0) of - false -> - bsm_do_an_var(V, S, Cs, [C0|Acc]); - true -> - bsm_problem(C0, bin_var_used) - end - end; -bsm_do_an_var(_, _, [], Acc) -> reverse(Acc). - -bsm_annotate_for_reuse(#c_var{anno=Anno}=Var) -> - case member(reuse_for_context, Anno) of - false -> Var#c_var{anno=[reuse_for_context|Anno]}; - true -> Var - end. - -bsm_is_var_used(V, G, B) -> - core_lib:is_var_used(V, G) orelse core_lib:is_var_used(V, B). - -bsm_maybe_ctx_to_binary(V, B) -> - case core_lib:is_var_used(V, B) andalso not previous_ctx_to_binary(V, B) of - false -> - B; - true -> - #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary}, - args=[#c_var{name=V}]}, - body=B} - end. - -previous_ctx_to_binary(V, Core) -> - case Core of - #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary}, - args=[#c_var{name=V}]}} -> - true; - _ -> - false - end. - -%% bsm_leftmost(Cs) -> none | ArgumentNumber -%% Find the leftmost argument that does binary matching. Return -%% the number of the argument (1-N). - -bsm_leftmost(Cs) -> - bsm_leftmost_1(Cs, none). - -bsm_leftmost_1([#c_clause{pats=Ps}|Cs], Pos) -> - bsm_leftmost_2(Ps, Cs, 1, Pos); -bsm_leftmost_1([], Pos) -> Pos. - -bsm_leftmost_2(_, Cs, Pos, Pos) -> - bsm_leftmost_1(Cs, Pos); -bsm_leftmost_2([#c_binary{}|_], Cs, N, _) -> - bsm_leftmost_1(Cs, N); -bsm_leftmost_2([_|Ps], Cs, N, Pos) -> - bsm_leftmost_2(Ps, Cs, N+1, Pos); -bsm_leftmost_2([], Cs, _, Pos) -> - bsm_leftmost_1(Cs, Pos). - -%% bsm_nonempty(Cs, Pos) -> true|false -%% Check if at least one of the clauses matches a non-empty -%% binary in the given argument position. -%% -bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) -> - case nth(Pos, Ps) of - #c_binary{segments=[_|_]} -> - true; - _ -> - bsm_nonempty(Cs, Pos) - end; -bsm_nonempty([], _ ) -> false. - -%% bsm_ensure_no_partition(Cs, Pos) -> ok (exception if problem) -%% We must make sure that matching is not partitioned between -%% variables like this: -%% foo(<<...>>) -> ... -%% foo(<Variable>) when ... -> ... -%% foo(<Any non-variable pattern>) -> -%% If there is such partition, we are not allowed to reuse the binary variable -%% for the match context. -%% -%% Also, arguments to the left of the argument that is matched -%% against a binary, are only allowed to be simple variables, not -%% used in guards. The reason is that we must know that the binary is -%% only matched in one place (i.e. there must be only one bs_start_match2 -%% instruction emitted). - -bsm_ensure_no_partition(Cs, Pos) -> - bsm_ensure_no_partition_1(Cs, Pos, before). - -%% Loop through each clause. -bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], Pos, State0) -> - State = bsm_ensure_no_partition_2(Ps, Pos, G, simple_vars, State0), - case State of - 'after' -> - bsm_ensure_no_partition_after(Cs, Pos); - _ -> - ok - end, - bsm_ensure_no_partition_1(Cs, Pos, State); -bsm_ensure_no_partition_1([], _, _) -> ok. - -%% Loop through each pattern for this clause. -bsm_ensure_no_partition_2([#c_binary{}=Where|_], 1, _, Vstate, State) -> - case State of - before when Vstate =:= simple_vars -> within; - before -> bsm_problem(Where, Vstate); - within when Vstate =:= simple_vars -> within; - within -> bsm_problem(Where, Vstate) - end; -bsm_ensure_no_partition_2([#c_alias{}=Alias|_], 1, N, Vstate, State) -> - %% Retrieve the real pattern that the alias refers to and check that. - P = bsm_real_pattern(Alias), - bsm_ensure_no_partition_2([P], 1, N, Vstate, State); -bsm_ensure_no_partition_2([_|_], 1, _, _Vstate, before=State) -> - %% No binary matching yet - therefore no partition. - State; -bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) -> - case bsm_could_match_binary(P) of - false -> - %% If clauses can be freely arranged (Vstate =:= simple_vars), - %% a clause that cannot match a binary will not partition the clause. - %% Example: - %% - %% a(Var, <<>>) -> ... - %% a(Var, []) -> ... - %% a(Var, <<B>>) -> ... - %% - %% But if the clauses can't be freely rearranged, as in - %% - %% b(Var, <<X>>) -> ... - %% b(1, 2) -> ... - %% - %% we do have a problem. - %% - case Vstate of - simple_vars -> State; - _ -> bsm_problem(P, Vstate) - end; - true -> - %% The pattern P *may* match a binary, so we must update the state. - %% (P must be a variable.) - case State of - within -> 'after'; - 'after' -> 'after' - end - end; -bsm_ensure_no_partition_2([#c_var{name=V}|Ps], N, G, Vstate, S) -> - case core_lib:is_var_used(V, G) of - false -> - bsm_ensure_no_partition_2(Ps, N-1, G, Vstate, S); - true -> - bsm_ensure_no_partition_2(Ps, N-1, G, bin_left_var_used_in_guard, S) - end; -bsm_ensure_no_partition_2([_|Ps], N, G, _, S) -> - bsm_ensure_no_partition_2(Ps, N-1, G, bin_argument_order, S). - -bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs], Pos) -> - case nth(Pos, Ps) of - #c_var{} -> - bsm_ensure_no_partition_after(Cs, Pos); - _ -> - bsm_problem(C, bin_partition) - end; -bsm_ensure_no_partition_after([], _) -> ok. - -bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P); -bsm_could_match_binary(#c_cons{}) -> false; -bsm_could_match_binary(#c_tuple{}) -> false; -bsm_could_match_binary(#c_literal{val=Lit}) -> is_bitstring(Lit); -bsm_could_match_binary(_) -> true. - -bsm_real_pattern(#c_alias{pat=P}) -> bsm_real_pattern(P); -bsm_real_pattern(P) -> P. - -bsm_problem(Where, What) -> - throw({problem,Where,What}). %%% %%% Handling of warnings. @@ -3249,12 +3002,6 @@ bsm_problem(Where, What) -> init_warnings() -> put({?MODULE,warnings}, []). -add_bin_opt_info(Core, Term) -> - case get(bin_opt_info) of - true -> add_warning(Core, Term); - false -> ok - end. - add_warning(Core, Term) -> case should_suppress_warning(Core) of true -> @@ -3376,28 +3123,7 @@ format_error(result_ignored) -> format_error(invalid_call) -> "invalid function call"; format_error(useless_building) -> - "a term is constructed, but never used"; -format_error(bin_opt_alias) -> - "INFO: the '=' operator will prevent delayed sub binary optimization"; -format_error(bin_partition) -> - "INFO: matching non-variables after a previous clause matching a variable " - "will prevent delayed sub binary optimization"; -format_error(bin_left_var_used_in_guard) -> - "INFO: a variable to the left of the binary pattern is used in a guard; " - "will prevent delayed sub binary optimization"; -format_error(bin_argument_order) -> - "INFO: matching anything else but a plain variable to the left of " - "binary pattern will prevent delayed sub binary optimization; " - "SUGGEST changing argument order"; -format_error(bin_var_used) -> - "INFO: using a matched out sub binary will prevent " - "delayed sub binary optimization"; -format_error(orig_bin_var_used_in_guard) -> - "INFO: using the original binary variable in a guard will prevent " - "delayed sub binary optimization"; -format_error(bin_var_used_in_guard) -> - "INFO: using a matched out sub binary in a guard will prevent " - "delayed sub binary optimization". + "a term is constructed, but never used". -ifdef(DEBUG). %% In order for simplify_let/2 to work correctly, the list of diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 004c609311..1fc05109c5 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -1313,23 +1313,26 @@ get_vsub(V, Vsub) -> set_vsub(V, S, Vsub) -> orddict:store(V, S, Vsub). -subst_vsub(Key, New, [{K,Key}|Dict]) -> +subst_vsub(Key, New, Vsub) -> + orddict:from_list(subst_vsub_1(Key, New, Vsub)). + +subst_vsub_1(Key, New, [{K,Key}|Dict]) -> %% Fold chained substitution. - [{K,New}|subst_vsub(Key, New, Dict)]; -subst_vsub(Key, New, [{K,_}|_]=Dict) when Key < K -> + [{K,New}|subst_vsub_1(Key, New, Dict)]; +subst_vsub_1(Key, New, [{K,_}|_]=Dict) when Key < K -> %% Insert the new substitution here, and continue %% look for chained substitutions. - [{Key,New}|subst_vsub_1(Key, New, Dict)]; -subst_vsub(Key, New, [{K,_}=E|Dict]) when Key > K -> - [E|subst_vsub(Key, New, Dict)]; -subst_vsub(Key, New, []) -> [{Key,New}]. + [{Key,New}|subst_vsub_2(Key, New, Dict)]; +subst_vsub_1(Key, New, [{K,_}=E|Dict]) when Key > K -> + [E|subst_vsub_1(Key, New, Dict)]; +subst_vsub_1(Key, New, []) -> [{Key,New}]. -subst_vsub_1(V, S, [{K,V}|Dict]) -> +subst_vsub_2(V, S, [{K,V}|Dict]) -> %% Fold chained substitution. - [{K,S}|subst_vsub_1(V, S, Dict)]; -subst_vsub_1(V, S, [E|Dict]) -> - [E|subst_vsub_1(V, S, Dict)]; -subst_vsub_1(_, _, []) -> []. + [{K,S}|subst_vsub_2(V, S, Dict)]; +subst_vsub_2(V, S, [E|Dict]) -> + [E|subst_vsub_2(V, S, Dict)]; +subst_vsub_2(_, _, []) -> []. get_fsub(F, A, Fsub) -> case orddict:find({F,A}, Fsub) of diff --git a/lib/compiler/src/v3_kernel_pp.erl b/lib/compiler/src/v3_kernel_pp.erl index 716280a95c..53097d0d7d 100644 --- a/lib/compiler/src/v3_kernel_pp.erl +++ b/lib/compiler/src/v3_kernel_pp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2016. All Rights Reserved. +%% Copyright Ericsson AB 1999-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index 07dad85c57..86146c614f 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -22,7 +22,7 @@ -export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1, init_per_group/2,end_per_group/2, integers/1,coverage/1,booleans/1,setelement/1,cons/1, - tuple/1,record_float/1,binary_float/1]). + tuple/1,record_float/1,binary_float/1,float_compare/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -39,7 +39,8 @@ groups() -> cons, tuple, record_float, - binary_float + binary_float, + float_compare ]}]. init_per_suite(Config) -> @@ -151,5 +152,25 @@ binary_float(_Config) -> binary_negate_float(<<Float/float>>) -> <<-Float/float>>. +float_compare(_Config) -> + false = do_float_compare(-42.0), + false = do_float_compare(-42), + false = do_float_compare(0), + false = do_float_compare(0.0), + true = do_float_compare(42), + true = do_float_compare(42.0), + ok. + +do_float_compare(X) -> + %% ERL-433: Used to fail before OTP 20. Was accidentally fixed + %% in OTP 20. Add a test case to ensure it stays fixed. + + Y = X + 1.0, + case X > 0 of + T when (T =:= nil) or (T =:= false) -> T; + _T -> Y > 0 + end. + + id(I) -> I. diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index 75bfbf68cc..c23514b36b 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl index fd97eea4cb..da99aba346 100644 --- a/lib/compiler/test/bs_construct_SUITE.erl +++ b/lib/compiler/test/bs_construct_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index 89f851ac3b..0ec05456ec 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2016. All Rights Reserved. +%% Copyright Ericsson AB 2005-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ match_string_opt/1,select_on_integer/1, map_and_binary/1,unsafe_branch_caching/1, bad_literals/1,good_literals/1,constant_propagation/1, - parse_xml/1]). + parse_xml/1,get_payload/1]). -export([coverage_id/1,coverage_external_ignore/2]). @@ -70,7 +70,8 @@ groups() -> no_partition,calling_a_binary,binary_in_map, match_string_opt,select_on_integer, map_and_binary,unsafe_branch_caching, - bad_literals,good_literals,constant_propagation,parse_xml]}]. + bad_literals,good_literals,constant_propagation,parse_xml, + get_payload]}]. init_per_suite(Config) -> @@ -1508,6 +1509,20 @@ do_parse_xml(<<"<?xml"/utf8,Rest/binary>> = Bytes) -> is_next_char_whitespace(<<C/utf8,_/binary>>) -> C =:= $\s. +-record(ext_header, + {this_hdr = 17, + ext_hdr_opts}). + +get_payload(Config) -> + <<3445:48>> = do_get_payload(#ext_header{ext_hdr_opts = <<3445:48>>}), + {'EXIT',_} = (catch do_get_payload(#ext_header{})), + ok. + +do_get_payload(ExtHdr) -> + _ = ExtHdr#ext_header.this_hdr, + ExtHdrOptions = ExtHdr#ext_header.ext_hdr_opts, + <<_:13,_:35>> = ExtHdr#ext_header.ext_hdr_opts, + ExtHdrOptions. check(F, R) -> R = F(). diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index 4e2753ba5f..f647a4030d 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -371,6 +371,7 @@ do_file_listings(DataDir, PrivDir, [File|Files]) -> do_listing(Simple, TargetDir, dinline, ".inline"), do_listing(Simple, TargetDir, dcore, ".core"), do_listing(Simple, TargetDir, dcopt, ".copt"), + do_listing(Simple, TargetDir, dcbsm, ".core_bsm"), do_listing(Simple, TargetDir, dsetel, ".dsetel"), do_listing(Simple, TargetDir, dkern, ".kernel"), do_listing(Simple, TargetDir, dlife, ".life"), diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl index f8839da42f..0e07e8dd2e 100644 --- a/lib/compiler/test/core_SUITE.erl +++ b/lib/compiler/test/core_SUITE.erl @@ -28,7 +28,8 @@ map_core_test/1,eval_case/1,bad_boolean_guard/1, bs_shadowed_size_var/1, cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1, - cover_v3_kernel_4/1,cover_v3_kernel_5/1]). + cover_v3_kernel_4/1,cover_v3_kernel_5/1, + non_variable_apply/1]). -include_lib("common_test/include/ct.hrl"). @@ -56,7 +57,8 @@ groups() -> map_core_test,eval_case,bad_boolean_guard, bs_shadowed_size_var, cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3, - cover_v3_kernel_4,cover_v3_kernel_5 + cover_v3_kernel_4,cover_v3_kernel_5, + non_variable_apply ]}]. @@ -90,7 +92,7 @@ end_per_group(_GroupName, Config) -> ?comp(cover_v3_kernel_3). ?comp(cover_v3_kernel_4). ?comp(cover_v3_kernel_5). - +?comp(non_variable_apply). try_it(Mod, Conf) -> Src = filename:join(proplists:get_value(data_dir, Conf), diff --git a/lib/compiler/test/core_SUITE_data/non_variable_apply.core b/lib/compiler/test/core_SUITE_data/non_variable_apply.core new file mode 100644 index 0000000000..d9322cc455 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/non_variable_apply.core @@ -0,0 +1,80 @@ +module 'non_variable_apply' ['module_info'/0, + 'module_info'/1, + 'non_variable_apply'/0] + attributes [] + +'non_variable_apply'/0 = + %% Line 4 + fun () -> + case <> of + <> when 'true' -> + let <OkFun> = + fun (_@c0) -> + %% Line 5 + case _@c0 of + <'ok'> when 'true' -> + 'ok' + ( <_@c1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_@c1}) + -| [{'function_name',{'-non_variable_apply/0-fun-0-',1}}] ) + -| ['compiler_generated'] ) + end + in let <F> = + fun (_@c5,_@c4) -> + %% Line 6 + case <_@c5,_@c4> of + <F,X> when 'true' -> + apply apply 'id'/1 (F) (X) + ( <_@c7,_@c6> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_@c7,_@c6}) + -| [{'function_name',{'-non_variable_apply/0-fun-1-',2}}] ) + -| ['compiler_generated'] ) + end + in %% Line 9 + apply F + (OkFun, 'ok') + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'non_variable_apply',0}}] ) + -| ['compiler_generated'] ) + end +'id'/1 = + %% Line 11 + fun (_@c0) -> + case _@c0 of + <I> when 'true' -> + I + ( <_@c1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_@c1}) + -| [{'function_name',{'id',1}}] ) + -| ['compiler_generated'] ) + end +'module_info'/0 = + fun () -> + case <> of + <> when 'true' -> + call 'erlang':'get_module_info' + ('non_variable_apply') + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'module_info',0}}] ) + -| ['compiler_generated'] ) + end +'module_info'/1 = + fun (_@c0) -> + case _@c0 of + <X> when 'true' -> + call 'erlang':'get_module_info' + ('non_variable_apply', X) + ( <_@c1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_@c1}) + -| [{'function_name',{'module_info',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index 01b064cc10..4bd884d86b 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -161,11 +161,12 @@ md5_1(Beam) -> %% Cover some code that handles internal errors. silly_coverage(Config) when is_list(Config) -> - %% sys_core_fold, sys_core_setel, v3_kernel + %% sys_core_fold, sys_core_bsm, sys_core_setel, v3_kernel BadCoreErlang = {c_module,[], name,[],[], [{{c_var,[],{foo,2}},seriously_bad_body}]}, expect_error(fun() -> sys_core_fold:module(BadCoreErlang, []) end), + expect_error(fun() -> sys_core_bsm:module(BadCoreErlang, []) end), expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end), expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end), diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl index 7c27750556..857995b6a6 100644 --- a/lib/compiler/test/warnings_SUITE.erl +++ b/lib/compiler/test/warnings_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2016. All Rights Reserved. +%% Copyright Ericsson AB 2003-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -529,7 +529,7 @@ bin_opt_info(Config) when is_list(Config) -> Code, [bin_opt_info], {warnings, - [{4,sys_core_fold,orig_bin_var_used_in_guard}, + [{4,sys_core_bsm,orig_bin_var_used_in_guard}, {5,beam_bsm,{no_bin_opt,{{t1,1},no_suitable_bs_start_match}}}, {9,beam_bsm,{no_bin_opt, {binary_used_in,{extfunc,erlang,split_binary,2}}}} ]}}], diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 5c87304a01..463c264a5f 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 7.0.4 +COMPILER_VSN = 7.1 |
