aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/doc/src/compile.xml4
-rw-r--r--lib/compiler/doc/src/notes.xml61
-rw-r--r--lib/compiler/src/beam_bool.erl3
-rw-r--r--lib/compiler/src/beam_validator.erl1
-rw-r--r--lib/compiler/src/cerl_inline.erl39
-rw-r--r--lib/compiler/src/compile.erl31
-rw-r--r--lib/compiler/src/core_lint.erl4
-rwxr-xr-x[-rw-r--r--]lib/compiler/src/genop.tab244
-rw-r--r--lib/compiler/src/v3_core.erl6
-rw-r--r--lib/compiler/src/v3_kernel.erl2
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl9
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S15
-rw-r--r--lib/compiler/test/compile_SUITE.erl4
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl2
-rw-r--r--lib/compiler/test/guard_SUITE.erl8
-rw-r--r--lib/compiler/test/inline_SUITE.erl3
-rw-r--r--lib/compiler/test/inline_SUITE_data/fname.erl29
-rw-r--r--lib/compiler/test/warnings_SUITE.erl14
-rw-r--r--lib/compiler/vsn.mk2
19 files changed, 448 insertions, 33 deletions
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 96907f6b10..73d75851cf 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -859,6 +859,10 @@ pi() -> 3.1416.
{ErrorLine, Module, ErrorDescriptor}
</code>
+ <p><c>ErrorLine</c> will be the atom <c>none</c> if the error does
+ not correspond to a specific line (e.g. if the source file does
+ not exist).</p>
+
<p>A string describing the error is obtained with the following
call:</p>
<code>
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 837fcf4368..eb5fa8b398 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -31,6 +31,67 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 4.9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Expressions such as <c>'B = is_integer(V), if B and B
+ -&gt; ok end'</c> would crash the compiler.</p>
+ <p>
+ Own Id: OTP-11240</p>
+ </item>
+ <item>
+ <p>
+ <c>compile:file2/2</c> with the option
+ <c>report_errors</c> could return ErrorInfo tuples with
+ only two elements, while the documentation says that the
+ ErrorInfo tuple always has three elements. Also updated
+ the documentation to add that the first element may be
+ '<c>none</c>' if no line number is applicable.</p>
+ <p>
+ Own Id: OTP-11304 Aux Id: seq12412 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Fix matching of floating point middle-endian machines.
+ Thanks to Johannes Weissl.</p>
+ <p>
+ Own Id: OTP-11201</p>
+ </item>
+ <item>
+ <p>
+ Restrict inlining of local fun references. Thanks to
+ Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-11211</p>
+ </item>
+ <item>
+ <p>
+ Silence a misleading warning with some comprehensions.
+ Thanks to Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-11212</p>
+ </item>
+ <item>
+ <p>
+ Forbid returning a match context in beam_validator.
+ Thanks to Anthony Ramine.</p>
+ <p>
+ Own Id: OTP-11247</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 4.9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl
index cf5455dfde..124abd13c1 100644
--- a/lib/compiler/src/beam_bool.erl
+++ b/lib/compiler/src/beam_bool.erl
@@ -425,6 +425,9 @@ bopt_tree([], Forest, Pre) ->
safe_bool_op(N, Ar) ->
erl_internal:new_type_test(N, Ar) orelse erl_internal:comp_op(N, Ar).
+bopt_bool_args([V0,V0], Forest0) ->
+ {V,Forest} = bopt_bool_arg(V0, Forest0),
+ {[V,V],Forest};
bopt_bool_args(As, Forest) ->
mapfoldl(fun bopt_bool_arg/2, Forest, As).
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index eb72290306..70279ab658 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -628,6 +628,7 @@ valfun_4({gc_bif,Op,{f,Fail},Live,Src,Dst}, #vst{current=St0}=Vst0) ->
Type = bif_type(Op, Src, Vst),
set_type_reg(Type, Dst, Vst);
valfun_4(return, #vst{current=#st{numy=none}}=Vst) ->
+ assert_term({x,0}, Vst),
kill_state(Vst);
valfun_4(return, #vst{current=#st{numy=NumY}}) ->
error({stack_frame,NumY});
diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl
index 2e7554c1ff..c6de63c69f 100644
--- a/lib/compiler/src/cerl_inline.erl
+++ b/lib/compiler/src/cerl_inline.erl
@@ -52,7 +52,7 @@
clause_pats/1, clause_vars/1, concrete/1, cons_hd/1,
cons_tl/1, data_arity/1, data_es/1, data_type/1,
fun_body/1, fun_vars/1, get_ann/1, int_val/1,
- is_c_atom/1, is_c_cons/1, is_c_fun/1, is_c_int/1,
+ is_c_atom/1, is_c_cons/1, is_c_fname/1, is_c_int/1,
is_c_list/1, is_c_seq/1, is_c_tuple/1, is_c_var/1,
is_data/1, is_literal/1, is_literal_term/1, let_arg/1,
let_body/1, let_vars/1, letrec_body/1, letrec_defs/1,
@@ -1578,7 +1578,7 @@ make_let_binding_1(R, E, S) ->
%% completely.
copy(R, Opnd, E, Ctxt, Env, S) ->
- case is_c_var(E) of
+ case is_c_var(E) andalso not is_c_fname(E) of
true ->
%% The operand reduces to another variable - get its
%% ref-structure and attempt to propagate further.
@@ -1628,12 +1628,12 @@ copy_var(R, Ctxt, Env, S) ->
end.
copy_1(R, Opnd, E, Ctxt, Env, S) ->
- %% Fun-expression (lambdas) are a bit special; they are copyable,
- %% but should preferably not be duplicated, so they should not be
- %% copy propagated except into application contexts, where they can
- %% be inlined.
- case is_c_fun(E) of
- true ->
+ case type(E) of
+ 'fun' ->
+ %% Fun-expression (lambdas) are a bit special; they are copyable,
+ %% but should preferably not be duplicated, so they should not be
+ %% copy propagated except into application contexts, where they can
+ %% be inlined.
case Ctxt of
#app{} ->
%% First test if the operand is "outer-pending"; if
@@ -1649,7 +1649,28 @@ copy_1(R, Opnd, E, Ctxt, Env, S) ->
_ ->
residualize_var(R, S)
end;
- false ->
+ var ->
+ %% Variables at this point only refer to local functions; they are
+ %% copyable but can't appear in guards, so they should not be
+ %% copy propagated except into application contexts, where they can
+ %% be inlined.
+ case Ctxt of
+ #app{} ->
+ %% First test if the operand is "outer-pending"; if
+ %% so, don't inline.
+ case st__test_outer_pending(Opnd#opnd.loc, S) of
+ false ->
+ R1 = env__get(var_name(E), Opnd#opnd.env),
+ copy_var(R1, Ctxt, Env, S);
+ true ->
+ %% Cyclic reference forced inlining to stop
+ %% (avoiding infinite unfolding).
+ residualize_var(R, S)
+ end;
+ _ ->
+ residualize_var(R, S)
+ end;
+ _ ->
%% We have no other cases to handle here
residualize_var(R, S)
end.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 2ca403de54..802e3dfa2f 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -41,7 +41,8 @@
-type option() :: atom() | {atom(), term()} | {'d', atom(), term()}.
--type err_info() :: {erl_scan:line(), module(), term()}. %% ErrorDescriptor
+-type err_info() :: {erl_scan:line() | 'none',
+ module(), term()}. %% ErrorDescriptor
-type errors() :: [{file:filename(), [err_info()]}].
-type warnings() :: [{file:filename(), [err_info()]}].
-type mod_ret() :: {'ok', module()}
@@ -1290,10 +1291,10 @@ native_compile_1(St) ->
{error,R} ->
case IgnoreErrors of
true ->
- Ws = [{St#compile.ifile,[{?MODULE,{native,R}}]}],
+ Ws = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
{ok,St#compile{warnings=St#compile.warnings ++ Ws}};
false ->
- Es = [{St#compile.ifile,[{?MODULE,{native,R}}]}],
+ Es = [{St#compile.ifile,[{none,?MODULE,{native,R}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end
catch
@@ -1302,7 +1303,7 @@ native_compile_1(St) ->
case IgnoreErrors of
true ->
Ws = [{St#compile.ifile,
- [{?MODULE,{native_crash,R,Stk}}]}],
+ [{none,?MODULE,{native_crash,R,Stk}}]}],
{ok,St#compile{warnings=St#compile.warnings ++ Ws}};
false ->
erlang:raise(Class, R, Stk)
@@ -1349,7 +1350,7 @@ save_binary(#compile{module=Mod,ofile=Outfile,
save_binary_1(St);
_ ->
Es = [{St#compile.ofile,
- [{?MODULE,{module_name,Mod,Base}}]}],
+ [{none,?MODULE,{module_name,Mod,Base}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end
end.
@@ -1363,20 +1364,20 @@ save_binary_1(St) ->
ok ->
{ok,St};
{error,RenameError} ->
- Es0 = [{Ofile,[{?MODULE,{rename,Tfile,Ofile,
- RenameError}}]}],
+ Es0 = [{Ofile,[{none,?MODULE,{rename,Tfile,Ofile,
+ RenameError}}]}],
Es = case file:delete(Tfile) of
ok -> Es0;
{error,DeleteError} ->
Es0 ++
[{Ofile,
- [{?MODULE,{delete_temp,Tfile,
- DeleteError}}]}]
+ [{none,?MODULE,{delete_temp,Tfile,
+ DeleteError}}]}]
end,
{error,St#compile{errors=St#compile.errors ++ Es}}
end;
{error,_Error} ->
- Es = [{Tfile,[{compile,write_error}]}],
+ Es = [{Tfile,[{none,compile,write_error}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
@@ -1419,6 +1420,9 @@ report_warnings(#compile{options=Opts,warnings=Ws0}) ->
false -> ok
end.
+format_message(F, P, [{none,Mod,E}|Es]) ->
+ M = {none,io_lib:format("~ts: ~s~ts\n", [F,P,Mod:format_error(E)])},
+ [M|format_message(F, P, Es)];
format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) ->
M = {{F,Loc},io_lib:format("~ts:~w:~w ~s~ts\n",
[F,Line,Column,P,Mod:format_error(E)])},
@@ -1428,12 +1432,17 @@ format_message(F, P, [{Line,Mod,E}|Es]) ->
[F,Line,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(F, P, [{Mod,E}|Es]) ->
+ %% Not documented and not expected to be used any more, but
+ %% keep a while just in case.
M = {none,io_lib:format("~ts: ~s~ts\n", [F,P,Mod:format_error(E)])},
[M|format_message(F, P, Es)];
format_message(_, _, []) -> [].
%% list_errors(File, ErrorDescriptors) -> ok
+list_errors(F, [{none,Mod,E}|Es]) ->
+ io:fwrite("~ts: ~ts\n", [F,Mod:format_error(E)]),
+ list_errors(F, Es);
list_errors(F, [{{Line,Column},Mod,E}|Es]) ->
io:fwrite("~ts:~w:~w: ~ts\n", [F,Line,Column,Mod:format_error(E)]),
list_errors(F, Es);
@@ -1441,6 +1450,8 @@ list_errors(F, [{Line,Mod,E}|Es]) ->
io:fwrite("~ts:~w: ~ts\n", [F,Line,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(F, [{Mod,E}|Es]) ->
+ %% Not documented and not expected to be used any more, but
+ %% keep a while just in case.
io:fwrite("~ts: ~ts\n", [F,Mod:format_error(E)]),
list_errors(F, Es);
list_errors(_F, []) -> ok.
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index 1e8983f594..67d37ff1fc 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -68,7 +68,7 @@
| {'undefined_function', fa(), fa()}
| {'tail_segment_not_at_end', fa()}.
--type error() :: {module(), err_desc()}.
+-type error() :: {'none', module(), err_desc()}.
-type warning() :: {module(), term()}.
%%-----------------------------------------------------------------------
@@ -162,7 +162,7 @@ return_status(St) ->
%% add_warning(ErrorDescriptor, State) -> State'
%% Note that we don't use line numbers here.
-add_error(E, St) -> St#lint{errors=[{?MODULE,E}|St#lint.errors]}.
+add_error(E, St) -> St#lint{errors=[{none,?MODULE,E}|St#lint.errors]}.
%%add_warning(W, St) -> St#lint{warnings=[{none,core_lint,W}|St#lint.warnings]}.
diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab
index 75ac91907a..ebc9b1c85b 100644..100755
--- a/lib/compiler/src/genop.tab
+++ b/lib/compiler/src/genop.tab
@@ -23,45 +23,148 @@ BEAM_FORMAT_NUMBER=0
# arity or semantics, the format number above must be bumped.
#
+## @spec label Lbl
+## @doc Specify a module local label.
+## Label gives this code address a name (Lbl) and marks the start of
+## a basic block.
1: label/1
+
+## @spec func_info M F A
+## @doc Define a function M:F/A
2: func_info/3
+
3: int_code_end/0
#
# Function and BIF calls.
#
+
+## @spec call Arity Label
+## @doc Call the function at Label.
+## Save the next instruction as the return address in the CP register.
4: call/2
+
+## @spec call_last Arity Label Dellocate
+## @doc Deallocate and do a tail recursive call to the function at Label.
+## Do not update the CP register.
+## Before the call deallocate Deallocate words of stack.
5: call_last/3
+
+## @spec call_only Arity Label
+## @doc Do a tail recursive call to the function at Label.
+## Do not update the CP register.
6: call_only/2
+## @spec call_ext Arity Destination
+## @doc Call the function of arity Arity pointed to by Destination.
+## Save the next instruction as the return address in the CP register.
7: call_ext/2
+
+## @spec call_ext_last Arity Destination Deallocate
+## @doc Deallocate and do a tail call to function of arity Arity
+## pointed to by Destination.
+## Do not update the CP register.
+## Deallocate Deallocate words from the stack before the call.
8: call_ext_last/3
+## @spec bif0 Bif Reg
+## @doc Call the bif Bif and store the result in Reg.
9: bif0/2
+
+## @spec bif1 Lbl Bif Arg Reg
+## @doc Call the bif Bif with the argument Arg, and store the result in Reg.
+## On failure jump to Lbl.
10: bif1/4
+
+## @spec bif2 Lbl Bif Arg1 Arg2 Reg
+## @doc Call the bif Bif with the arguments Arg1 and Arg2,
+## and store the result in Reg.
+## On failure jump to Lbl.
11: bif2/5
#
# Allocating, deallocating and returning.
#
+
+## @spec allocate StackNeed Live
+## @doc Allocate space for StackNeed words on the stack. If a GC is needed
+## during allocation there are Live number of live X registers.
+## Also save the continuation pointer (CP) on the stack.
12: allocate/2
+
+## @spec allocate_heap StackNeed HeapNeed Live
+## @doc Allocate space for StackNeed words on the stack and ensure there is
+## space for HeapNeed words on the heap. If a GC is needed
+## save Live number of X registers.
+## Also save the continuation pointer (CP) on the stack.
13: allocate_heap/3
+
+## @spec allocate_zero StackNeed Live
+## @doc Allocate space for StackNeed words on the stack. If a GC is needed
+## during allocation there are Live number of live X registers.
+## Clear the new stack words. (By writing NIL.)
+## Also save the continuation pointer (CP) on the stack.
14: allocate_zero/2
+
+## @spec allocate_heap_zero StackNeed HeapNeed Live
+## @doc Allocate space for StackNeed words on the stack and HeapNeed words
+## on the heap. If a GC is needed
+## during allocation there are Live number of live X registers.
+## Clear the new stack words. (By writing NIL.)
+## Also save the continuation pointer (CP) on the stack.
15: allocate_heap_zero/3
+
+## @spec test_heap HeapNeed Live
+## @doc Ensure there is space for HeapNeed words on the heap. If a GC is needed
+## save Live number of X registers.
16: test_heap/2
+
+## @spec init N
+## @doc Clear the Nth stack word. (By writing NIL.)
17: init/1
+
+## @spec deallocate N
+## @doc Restore the continuation pointer (CP) from the stack and deallocate
+## N+1 words from the stack (the + 1 is for the CP).
18: deallocate/1
+
+## @spec return
+## @doc Return to the address in the continuation pointer (CP).
19: return/0
#
# Sending & receiving.
#
+## @spec send
+## @doc Send argument in x(0) as a message to the destination process in x(0).
+## The message in x(1) ends up as the result of the send in x(0).
20: send/0
+
+## @spec remove_message
+## @doc Unlink the current message from the message queue and store a
+## pointer to the message in x(0). Remove any timeout.
21: remove_message/0
+
+## @spec timeout
+## @doc Reset the save point of the mailbox and clear the timeout flag.
22: timeout/0
+
+## @spec loop_rec Label Source
+## @doc Loop over the message queue, if it is empty jump to Label.
23: loop_rec/2
+
+## @spec loop_rec_end Label
+## @doc Advance the save pointer to the next message and jump back to Label.
24: loop_rec_end/1
+
+## @spec wait Label
+## @doc Suspend the processes and set the entry point to the beginning of the
+## receive loop at Label.
25: wait/1
+
+## @spec wait_timeout Lable Time
+## @doc Sets up a timeout of Time milllisecons and saves the address of the
+## following instruction as the entry point if the timeout triggers.
26: wait_timeout/2
#
@@ -83,36 +186,106 @@ BEAM_FORMAT_NUMBER=0
#
# Comparision operators.
#
+
+## @spec is_lt Lbl Arg1 Arg2
+## @doc Compare two terms and jump to Lbl if Arg1 is not less than Arg2.
39: is_lt/3
+
+## @spec is_ge Lbl Arg1 Arg2
+## @doc Compare two terms and jump to Lbl if Arg1 is less than Arg2.
40: is_ge/3
+
+## @spec is_eq Lbl Arg1 Arg2
+## @doc Compare two terms and jump to Lbl if Arg1 is not (numerically) equal to Arg2.
41: is_eq/3
+
+## @spec is_ne Lbl Arg1 Arg2
+## @doc Compare two terms and jump to Lbl if Arg1 is (numerically) equal to Arg2.
42: is_ne/3
+
+## @spec is_eq_exact Lbl Arg1 Arg2
+## @doc Compare two terms and jump to Lbl if Arg1 is not exactly equal to Arg2.
43: is_eq_exact/3
+
+## @spec is_ne_exact Lbl Arg1 Arg2
+## @doc Compare two terms and jump to Lbl if Arg1 is exactly equal to Arg2.
44: is_ne_exact/3
#
# Type tests.
#
+
+## @spec is_integer Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not an integer.
45: is_integer/2
+
+## @spec is_float Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a float.
46: is_float/2
+
+## @spec is_number Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a number.
47: is_number/2
+
+## @spec is_atom Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not an atom.
48: is_atom/2
+
+## @spec is_pid Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a pid.
49: is_pid/2
+
+## @spec is_reference Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a reference.
50: is_reference/2
+
+## @spec is_port Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a port.
51: is_port/2
+
+## @spec is_nil Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not nil.
52: is_nil/2
+
+## @spec is_binary Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a binary.
53: is_binary/2
+
54: -is_constant/2
+
+## @spec is_list Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a cons or nil.
55: is_list/2
+
+## @spec is_nonempty_list Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a cons.
56: is_nonempty_list/2
+
+## @spec is_tuple Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a tuple.
57: is_tuple/2
+
+## @spec test_arity Lbl Arg1 Arity
+## @doc Test the arity of (the tuple in) Arg1 and jump
+## to Lbl if it is not equal to Arity.
58: test_arity/3
#
# Indexing & jumping.
#
+
+## @spec select_val Arg FailLabel Destinations
+## @doc Jump to the destination label corresponding to Arg
+## in the Destinations list, if no arity matches, jump to FailLabel.
59: select_val/3
+
+## @spec select_tuple_arity Tuple FailLabel Destinations
+## @doc Check the arity of the tuple Tuple and jump to the corresponding
+## destination label, if no arity matches, jump to FailLabel.
60: select_tuple_arity/3
+
+## @spec jump Label
+## @doc Jump to Label.
61: jump/1
#
@@ -124,9 +297,26 @@ BEAM_FORMAT_NUMBER=0
#
# Moving, extracting, modifying.
#
+
+## @spec move Source Destination
+## @doc Move the source Source (a literal or a register) to
+## the destination register Destination.
64: move/2
+
+## @spec get_list Source Head Tail
+## @doc Get the head and tail (or car and cdr) parts of a list
+## (a cons cell) from Source and put them into the registers
+## Head and Tail.
65: get_list/3
+
+## @spec get_tuple_element Source Element Destination
+## @doc Get element number Element from the tuple in Source and put
+## it in the destination register Destination.
66: get_tuple_element/3
+
+## @spec set_tuple_element NewElement Tuple Position
+## @doc Update the element at postition Position of the tuple Tuple
+## with the new element NewElement.
67: set_tuple_element/3
#
@@ -147,13 +337,26 @@ BEAM_FORMAT_NUMBER=0
#
# 'fun' support.
#
+## @spec call_fun Arity
+## @doc Call a fun of arity Arity. Assume arguments in
+## registers x(0) to x(Arity-1) and that the fun is in x(Arity).
+## Save the next instruction as the return address in the CP register.
75: call_fun/1
+
76: -make_fun/3
+
+## @spec is_function Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a
+## function (i.e. fun or closure).
77: is_function/2
#
# Late additions to R5.
#
+
+## @spec call_ext_only Arity Label
+## Do a tail recursive call to the function at Label.
+## Do not update the CP register.
78: call_ext_only/2
#
@@ -212,9 +415,14 @@ BEAM_FORMAT_NUMBER=0
111: bs_add/5
112: apply/1
113: apply_last/2
+## @spec is_boolean Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a Boolean.
114: is_boolean/2
# New instructions in R10B-6.
+## @spec is_function2 Lbl Arg1 Arity
+## @doc Test the type of Arg1 and jump to Lbl if it is not a
+## function of arity Arity.
115: is_function2/3
# New bit syntax matching in R11B.
@@ -229,7 +437,20 @@ BEAM_FORMAT_NUMBER=0
123: bs_restore2/2
# New GC bifs introduced in R11B.
+
+## @spec gc_bif1 Lbl Live Bif Arg Reg
+## @doc Call the bif Bif with the argument Arg, and store the result in Reg.
+## On failure jump to Lbl.
+## Do a garbage collection if necessary to allocate space on the heap
+## for the result (saving Live number of X registers).
124: gc_bif1/5
+
+## @spec gc_bif2 Lbl Live Bif Arg1 Arg2 Reg
+## @doc Call the bif Bif with the arguments Arg1 and Arg2,
+## and store the result in Reg.
+## On failure jump to Lbl.
+## Do a garbage collection if necessary to allocate space on the heap
+## for the result (saving Live number of X registers).
125: gc_bif2/6
# Experimental new bit_level bifs introduced in R11B.
@@ -241,6 +462,8 @@ BEAM_FORMAT_NUMBER=0
128: -put_literal/2
# R11B-5
+## @spec is_bitstr Lbl Arg1
+## @doc Test the type of Arg1 and jump to Lbl if it is not a bit string.
129: is_bitstr/2
# R12B
@@ -250,7 +473,12 @@ BEAM_FORMAT_NUMBER=0
133: bs_init_writable/0
134: bs_append/8
135: bs_private_append/6
+
+## @spec trim N Remaining
+## @doc Reduce the stack usage by N words,
+## keeping the CP on the top of the stack.
136: trim/2
+
137: bs_init_bits/6
# R12B-5
@@ -277,8 +505,24 @@ BEAM_FORMAT_NUMBER=0
# R14A
+## @spec recv_mark Label
+## @doc Save the end of the message queue and the address of
+## the label Label so that a recv_set instruction can start
+## scanning the inbox from this position.
150: recv_mark/1
+
+## @spec recv_set Label
+## @doc Check that the saved mark points to Label and set the
+## save pointer in the message queue to the last position
+## of the message queue saved by the recv_mark instruction.
151: recv_set/1
+
+## @spec gc_bif3 Lbl Live Bif Arg1 Arg2 Arg3 Reg
+## @doc Call the bif Bif with the arguments Arg1, Arg2 and Arg3,
+## and store the result in Reg.
+## On failure jump to Lbl.
+## Do a garbage collection if necessary to allocate space on the heap
+## for the result (saving Live number of X registers).
152: gc_bif3/7
# R15A
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 70822f348e..89319af502 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -962,7 +962,8 @@ lc_tq(Line, E, [Fil0|Qs0], Mc, St0) ->
args=[],
clauses=[#iclause{anno=LAnno,pats=[],
guard=Gs,body=Lps ++ [Lc]}],
- fc=#iclause{anno=LAnno,pats=[],guard=[],body=[Mc]}},
+ fc=#iclause{anno=LAnno#a{anno=[compiler_generated|LA]},
+ pats=[],guard=[],body=[Mc]}},
[],St2};
false ->
{Lc,Lps,St1} = lc_tq(Line, E, Qs0, Mc, St0),
@@ -1107,7 +1108,8 @@ bc_tq1(Line, E, [Fil0|Qs0], AccVar, St0) ->
clauses=[#iclause{anno=LAnno,
pats=[],
guard=Gs,body=Bps ++ [Bc]}],
- fc=#iclause{anno=LAnno,pats=[],guard=[],body=[AccVar]}},
+ fc=#iclause{anno=LAnno#a{anno=[compiler_generated|LA]},
+ pats=[],guard=[],body=[AccVar]}},
[],St};
false ->
{Bc,Bps,St1} = bc_tq1(Line, E, Qs0, AccVar, St0),
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 5f1c108f7c..2b2b8bf550 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1875,7 +1875,7 @@ format_error(bad_segment_size) ->
add_warning(none, Term, Anno, #kern{ws=Ws}=St) ->
File = get_file(Anno),
- St#kern{ws=[{File,[{?MODULE,Term}]}|Ws]};
+ St#kern{ws=[{File,[{none,?MODULE,Term}]}|Ws]};
add_warning(Line, Term, Anno, #kern{ws=Ws}=St) ->
File = get_file(Anno),
St#kern{ws=[{File,[{Line,?MODULE,Term}]}|Ws]}.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index bc1a9e2b3b..626f89ba7a 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -28,7 +28,7 @@
overwrite_catchtag/1,overwrite_trytag/1,accessing_tags/1,bad_catch_try/1,
cons_guard/1,
freg_range/1,freg_uninit/1,freg_state/1,
- bin_match/1,bin_aligned/1,bad_dsetel/1,
+ bin_match/1,bad_bin_match/1,bin_aligned/1,bad_dsetel/1,
state_after_fault_in_catch/1,no_exception_in_catch/1,
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1]).
@@ -56,7 +56,7 @@ groups() ->
unsafe_catch,dead_code,mult_labels,
overwrite_catchtag,overwrite_trytag,accessing_tags,
bad_catch_try,cons_guard,freg_range,freg_uninit,
- freg_state,bin_match,bin_aligned,bad_dsetel,
+ freg_state,bin_match,bad_bin_match,bin_aligned,bad_dsetel,
state_after_fault_in_catch,no_exception_in_catch,
undef_label,illegal_instruction,failing_gc_guard_bif]}].
@@ -317,6 +317,11 @@ bin_match(Config) when is_list(Config) ->
{{t,x,1},{{bs_restore,1},16,{no_save_point,1}}}] = Errors,
ok.
+bad_bin_match(Config) when is_list(Config) ->
+ [{{t,t,1},{return,5,{match_context,{x,0}}}}] =
+ do_val(bad_bin_match, Config),
+ ok.
+
bin_aligned(Config) when is_list(Config) ->
Errors = do_val(bin_aligned, Config),
?line
diff --git a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
new file mode 100644
index 0000000000..a60ca1e89a
--- /dev/null
+++ b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
@@ -0,0 +1,15 @@
+{module, bad_bin_match}. %% version = 0
+
+{exports, [{t,1}]}.
+
+{attributes, []}.
+
+{labels, 3}.
+
+
+{function, t, 1, 2}.
+ {label,1}.
+ {func_info,{atom,t},{atom,t},1}.
+ {label,2}.
+ {test,bs_start_match2,{f,1},1,[{x,0},0],{x,0}}.
+ return.
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index da8aecdc8b..66ce6c00ab 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -139,8 +139,8 @@ forms_2(Config) when is_list(Config) ->
module_mismatch(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "wrong_module_name.erl"),
- ?line {error,[{"wrong_module_name.beam",
- [{compile,{module_name,arne,"wrong_module_name"}}]}],
+ {error,[{"wrong_module_name.beam",
+ [{none,compile,{module_name,arne,"wrong_module_name"}}]}],
[]} = compile:file(File, [return]),
?line error = compile:file(File, [report]),
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index abc9ab6a72..a5a4e62a42 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -299,7 +299,7 @@ unused_multiple_values_error(Config) when is_list(Config) ->
Opts = [no_copt,clint,return,from_core,{outdir,PrivDir}
|test_lib:opt_opts(?MODULE)],
{error,[{unused_multiple_values_error,
- [{core_lint,{return_mismatch,{hello,1}}}]}],
+ [{none,core_lint,{return_mismatch,{hello,1}}}]}],
[]} = c:c(Core, Opts),
ok.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 5656d23090..a0a9bb7ddd 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -813,8 +813,16 @@ and_guard(Config) when is_list(Config) ->
?line ok = relprod({'Set',a,b}, {'Set',a,b}),
+ ok = and_same_var(42),
+ {'EXIT',{if_clause,_}} = (catch and_same_var(x)),
ok.
+and_same_var(V) ->
+ B = is_integer(V),
+ if
+ B or B -> ok
+ end.
+
relprod(R1, R2) when (erlang:size(R1) =:= 3) and (erlang:element(1,R1) =:= 'Set'), (erlang:size(R2) =:= 3) and (erlang:element(1,R2) =:= 'Set') ->
ok.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index d9b92766e4..e5c2d4f73a 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -36,7 +36,7 @@ all() ->
groups() ->
[{p,test_lib:parallel(),
- [attribute,bsdecode,bsdes,barnes2,decode1,smith,
+ [attribute,bsdecode,bsdes,barnes2,decode1,smith,fname,
itracer,pseudoknot,comma_splitter,lists,really_inlined,otp_7223,
coverage]}].
@@ -84,6 +84,7 @@ attribute(Config) when is_list(Config) ->
?comp(itracer).
?comp(pseudoknot).
?comp(comma_splitter).
+?comp(fname).
try_inline(Mod, Config) ->
Node = ?config(testing_node, Config),
diff --git a/lib/compiler/test/inline_SUITE_data/fname.erl b/lib/compiler/test/inline_SUITE_data/fname.erl
new file mode 100644
index 0000000000..7ad4446bf3
--- /dev/null
+++ b/lib/compiler/test/inline_SUITE_data/fname.erl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2013. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(fname).
+-export([?MODULE/0]).
+
+?MODULE() ->
+ F = fun bar/1,
+ G = lists:last([(fun (X) when F =:= X -> X end)]),
+ F = G(F),
+ ok.
+
+bar(X) ->
+ X.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index f00bfe663b..810b2b48c9 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -37,7 +37,7 @@
-export([pattern/1,pattern2/1,pattern3/1,pattern4/1,
guard/1,bad_arith/1,bool_cases/1,bad_apply/1,
- files/1,effect/1,bin_opt_info/1,bin_construction/1]).
+ files/1,effect/1,bin_opt_info/1,bin_construction/1, comprehensions/1]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(2)).
@@ -61,7 +61,7 @@ groups() ->
[{p,test_lib:parallel(),
[pattern,pattern2,pattern3,pattern4,guard,
bad_arith,bool_cases,bad_apply,files,effect,
- bin_opt_info,bin_construction]}].
+ bin_opt_info,bin_construction,comprehensions]}].
init_per_suite(Config) ->
Config.
@@ -536,6 +536,16 @@ bin_construction(Config) when is_list(Config) ->
ok.
+comprehensions(Config) when is_list(Config) ->
+ Ts = [{tautologic_guards,
+ <<"
+ f() -> [ true || true ].
+ g() -> << <<1>> || true >>.
+ ">>,
+ [], []}],
+ run(Config, Ts),
+ ok.
+
%%%
%%% End of test cases.
%%%
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 1c6f49d89b..8cfd8d294e 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 4.9.2
+COMPILER_VSN = 4.9.3