aboutsummaryrefslogtreecommitdiffstats
path: root/lib/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler')
-rw-r--r--lib/compiler/src/beam_dict.erl13
-rw-r--r--lib/compiler/src/sys_core_fold.erl192
-rw-r--r--lib/compiler/src/v3_core.erl69
-rw-r--r--lib/compiler/test/Makefile2
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl9
-rw-r--r--lib/compiler/test/warnings_SUITE.erl10
6 files changed, 176 insertions, 119 deletions
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index a503fcab38..c50ed28aa9 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -36,7 +36,6 @@
strings = <<>> :: binary(), %String pool
lambdas = [], %[{...}]
literals = dict:new() :: dict(), %Format: {Literal,Number}
- next_atom = 1 :: pos_integer(),
next_import = 0 :: non_neg_integer(),
string_offset = 0 :: non_neg_integer(),
next_literal = 0 :: non_neg_integer(),
@@ -66,13 +65,14 @@ highest_opcode(#asm{highest_opcode=Op}) -> Op.
%% atom(Atom, Dict) -> {Index,Dict'}
-spec atom(atom(), bdict()) -> {pos_integer(), bdict()}.
-atom(Atom, #asm{atoms=Atoms0,next_atom=NextIndex}=Dict) when is_atom(Atom) ->
+atom(Atom, #asm{atoms=Atoms0}=Dict) when is_atom(Atom) ->
case gb_trees:lookup(Atom, Atoms0) of
{value,Index} ->
{Index,Dict};
none ->
+ NextIndex = gb_trees:size(Atoms0) + 1,
Atoms = gb_trees:insert(Atom, NextIndex, Atoms0),
- {NextIndex,Dict#asm{atoms=Atoms,next_atom=NextIndex+1}}
+ {NextIndex,Dict#asm{atoms=Atoms}}
end.
%% Remembers an exported function.
@@ -139,7 +139,7 @@ lambda(Lbl, Index, OldUniq, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0],
{OldIndex,Dict#asm{lambdas=Lambdas}}.
-%% Returns the index for a literal (adding it to the atom table if necessary).
+%% Returns the index for a literal (adding it to the literal table if necessary).
%% literal(Literal, Dict) -> {Index,Dict'}
-spec literal(term(), bdict()) -> {non_neg_integer(), bdict()}.
@@ -156,14 +156,15 @@ literal(Lit, #asm{literals=Tab0,next_literal=NextIndex}=Dict) ->
%% atom_table(Dict) -> {LastIndex,[Length,AtomString...]}
-spec atom_table(bdict()) -> {non_neg_integer(), [[non_neg_integer(),...]]}.
-atom_table(#asm{atoms=Atoms,next_atom=NumAtoms}) ->
+atom_table(#asm{atoms=Atoms}) ->
+ NumAtoms = gb_trees:size(Atoms),
Sorted = lists:keysort(2, gb_trees:to_list(Atoms)),
Fun = fun({A,_}) ->
L = atom_to_list(A),
[length(L)|L]
end,
AtomTab = lists:map(Fun, Sorted),
- {NumAtoms-1,AtomTab}.
+ {NumAtoms,AtomTab}.
%% Returns the table of local functions.
%% local_table(Dict) -> {NumLocals, [{Function, Arity, Label}...]}
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 96015fbe58..9360556e00 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -460,7 +460,8 @@ eval_binary(#c_binary{anno=Anno,segments=Ss}=Bin) ->
Bin;
throw:{badarg,Warning} ->
add_warning(Bin, Warning),
- #c_call{module=#c_literal{val=erlang},
+ #c_call{anno=Anno,
+ module=#c_literal{val=erlang},
name=#c_literal{val=error},
args=[#c_literal{val=badarg}]}
end.
@@ -658,36 +659,34 @@ call_0(Call, M, N, As0, Sub) ->
%% We inline some very common higher order list operations.
%% We use the same evaluation order as the library function.
-call_1(_Call, lists, all, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, all, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^all',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
Err1 = #c_tuple{es=[#c_literal{val='case_clause'}, X]},
CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
- body=#c_apply{op=Loop, args=[Xs]}},
+ body=#c_apply{anno=Anno, op=Loop, args=[Xs]}},
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=#c_literal{val=false}},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err1]}},
+ body=match_fail(Anno, Err1)},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_case{arg=#c_apply{op=F, args=[X]},
+ body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=true}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err2]}},
+ body=match_fail(Anno, Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, any, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, any, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^any',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -696,72 +695,71 @@ call_1(_Call, lists, any, [Arg1,Arg2], Sub) ->
CC1 = #c_clause{pats=[#c_literal{val=true}], guard=#c_literal{val=true},
body=#c_literal{val=true}},
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
- body=#c_apply{op=Loop, args=[Xs]}},
+ body=#c_apply{anno=Anno, op=Loop, args=[Xs]}},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err1]}},
+ body=match_fail(Anno, Err1)},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_case{arg=#c_apply{op=F, args=[X]},
+ body=#c_case{arg=#c_apply{anno=Anno, op=F, args=[X]},
clauses = [CC1, CC2, CC3]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=false}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err2]}},
+ body=match_fail(Anno, Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, foreach, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, foreach, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^foreach',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_seq{arg=#c_apply{op=F, args=[X]},
- body=#c_apply{op=Loop, args=[Xs]}}},
+ body=#c_seq{arg=#c_apply{anno=Anno, op=F, args=[X]},
+ body=#c_apply{anno=Anno, op=Loop, args=[Xs]}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=ok}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, map, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, map, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^map',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
H = #c_var{name='H'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_let{vars=[H], arg=#c_apply{op=F, args=[X]},
+ body=#c_let{vars=[H], arg=#c_apply{anno=Anno,
+ op=F,
+ args=[X]},
body=#c_cons{hd=H,
- tl=#c_apply{op=Loop,
+ tl=#c_apply{anno=Anno,
+ op=Loop,
args=[Xs]}}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=[]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, flatmap, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^flatmap',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -769,26 +767,27 @@ call_1(_Call, lists, flatmap, [Arg1,Arg2], Sub) ->
H = #c_var{name='H'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[H],
- arg=#c_apply{op=F, args=[X]},
- body=#c_call{module=#c_literal{val=erlang},
+ arg=#c_apply{anno=Anno, op=F, args=[X]},
+ body=#c_call{anno=Anno,
+ module=#c_literal{val=erlang},
name=#c_literal{val='++'},
args=[H,
- #c_apply{op=Loop,
+ #c_apply{anno=Anno,
+ op=Loop,
args=[Xs]}]}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=[]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, filter, [Arg1,Arg2], Sub) ->
+call_1(#c_call{anno=Anno}, lists, filter, [Arg1,Arg2], Sub) ->
Loop = #c_var{name={'lists^filter',1}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -800,72 +799,75 @@ call_1(_Call, lists, filter, [Arg1,Arg2], Sub) ->
CC2 = #c_clause{pats=[#c_literal{val=false}], guard=#c_literal{val=true},
body=Xs},
CC3 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err1]}},
+ body=match_fail(Anno, Err1)},
Case = #c_case{arg=B, clauses = [CC1, CC2, CC3]},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
body=#c_let{vars=[B],
- arg=#c_apply{op=F, args=[X]},
+ arg=#c_apply{anno=Anno, op=F, args=[X]},
body=#c_let{vars=[Xs],
- arg=#c_apply{op=Loop,
+ arg=#c_apply{anno=Anno,
+ op=Loop,
args=[Xs]},
body=Case}}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true},
body=#c_literal{val=[]}},
Err2 = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err2]}},
+ body=match_fail(Anno, Err2)},
Fun = #c_fun{vars=[Xs],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, L], arg=#c_values{es=[Arg1, Arg2]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L]}}},
Sub);
-call_1(_Call, lists, foldl, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, foldl, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^foldl',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
A = #c_var{name='A'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_apply{op=Loop,
- args=[Xs, #c_apply{op=F, args=[X, A]}]}},
+ body=#c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, #c_apply{anno=Anno,
+ op=F,
+ args=[X, A]}]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L, A]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}},
Sub);
-call_1(_Call, lists, foldr, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, foldr, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^foldr',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
X = #c_var{name='X'},
A = #c_var{name='A'},
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=#c_apply{op=F, args=[X, #c_apply{op=Loop,
- args=[Xs, A]}]}},
+ body=#c_apply{anno=Anno,
+ op=F,
+ args=[X, #c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, A]}]}},
C2 = #c_clause{pats=[#c_literal{val=[]}], guard=#c_literal{val=true}, body=A},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, A],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, A, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
- body=#c_apply{op=Loop, args=[L, A]}}},
+ body=#c_apply{anno=Anno, op=Loop, args=[L, A]}}},
Sub);
-call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^mapfoldl',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -876,15 +878,16 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E},
Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]},
C2 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
#c_case{arg=A, clauses=[C1, C2]}
end,
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
- body=Match(#c_apply{op=F, args=[X, Avar]},
+ body=Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
%%% Tuple passing version
- Match(#c_apply{op=Loop, args=[Xs, Avar]},
+ Match(#c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, Avar]},
#c_tuple{es=[Xs, Avar]},
#c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]})
%%% Multiple-value version
@@ -902,22 +905,23 @@ call_1(_Call, lists, mapfoldl, [Arg1,Arg2,Arg3], Sub) ->
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
%%% Tuple passing version
- body=#c_apply{op=Loop, args=[L, Avar]}}},
+ body=#c_apply{anno=Anno,
+ op=Loop,
+ args=[L, Avar]}}},
%%% Multiple-value version
%%% body=#c_let{vars=[Xs, A],
%%% arg=#c_apply{op=Loop,
%%% args=[L, A]},
%%% body=#c_tuple{es=[Xs, A]}}}},
Sub);
-call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
+call_1(#c_call{anno=Anno}, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
Loop = #c_var{name={'lists^mapfoldr',2}},
F = #c_var{name='F'},
Xs = #c_var{name='Xs'},
@@ -928,15 +932,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
C1 = #c_clause{pats=[P], guard=#c_literal{val=true}, body=E},
Err = #c_tuple{es=[#c_literal{val='badmatch'}, X]},
C2 = #c_clause{pats=[X], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
#c_case{arg=A, clauses=[C1, C2]}
end,
C1 = #c_clause{pats=[#c_cons{hd=X, tl=Xs}], guard=#c_literal{val=true},
%%% Tuple passing version
- body=Match(#c_apply{op=Loop, args=[Xs, Avar]},
+ body=Match(#c_apply{anno=Anno,
+ op=Loop,
+ args=[Xs, Avar]},
#c_tuple{es=[Xs, Avar]},
- Match(#c_apply{op=F, args=[X, Avar]},
+ Match(#c_apply{anno=Anno, op=F, args=[X, Avar]},
#c_tuple{es=[X, Avar]},
#c_tuple{es=[#c_cons{hd=X, tl=Xs}, Avar]}))
%%% Multiple-value version
@@ -955,15 +960,16 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
%%% body=#c_values{es=[#c_literal{val=[]}, A]}},
Err = #c_tuple{es=[#c_literal{val='function_clause'}, Xs]},
C3 = #c_clause{pats=[Xs], guard=#c_literal{val=true},
- body=#c_primop{name=#c_literal{val='match_fail'},
- args=[Err]}},
+ body=match_fail(Anno, Err)},
Fun = #c_fun{vars=[Xs, Avar],
body=#c_case{arg=Xs, clauses=[C1, C2, C3]}},
L = #c_var{name='L'},
expr(#c_let{vars=[F, Avar, L], arg=#c_values{es=[Arg1, Arg2, Arg3]},
body=#c_letrec{defs=[{Loop,Fun}],
%%% Tuple passing version
- body=#c_apply{op=Loop, args=[L, Avar]}}},
+ body=#c_apply{anno=Anno,
+ op=Loop,
+ args=[L, Avar]}}},
%%% Multiple-value version
%%% body=#c_let{vars=[Xs, A],
%%% arg=#c_apply{op=Loop,
@@ -973,6 +979,11 @@ call_1(_Call, lists, mapfoldr, [Arg1,Arg2,Arg3], Sub) ->
call_1(#c_call{module=M, name=N}=Call, _, _, As, Sub) ->
call_0(Call, M, N, As, Sub).
+match_fail(Anno, Arg) ->
+ #c_primop{anno=Anno,
+ name=#c_literal{val='match_fail'},
+ args=[Arg]}.
+
%% fold_call(Call, Mod, Name, Args, Sub) -> Expr.
%% Try to safely evaluate the call. Just try to evaluate arguments,
%% do the call and convert return values to literals. If this
@@ -1280,9 +1291,9 @@ eval_setelement_2(Pos, [H|T], NewVal) when Pos > 1 ->
%%
eval_failure(Call, Reason) ->
add_warning(Call, {eval_failure,Reason}),
- #c_call{module=#c_literal{val=erlang},
- name=#c_literal{val=error},
- args=[#c_literal{val=Reason}]}.
+ Call#c_call{module=#c_literal{val=erlang},
+ name=#c_literal{val=error},
+ args=[#c_literal{val=Reason}]}.
%% simplify_apply(Call0, Mod, Func, Args) -> Call
%% Simplify an apply/3 to a call if the number of arguments
@@ -1742,23 +1753,24 @@ opt_bool_clauses([_|_], _, _) ->
opt_bool_not(#c_case{arg=Arg,clauses=Cs0}=Case0) ->
case Arg of
- #c_call{module=#c_literal{val=erlang},
+ #c_call{anno=Anno,module=#c_literal{val=erlang},
name=#c_literal{val='not'},
args=[Expr]} ->
- Cs = opt_bool_not(Expr, Cs0),
+ Cs = opt_bool_not(Anno, Expr, Cs0),
Case = Case0#c_case{arg=Expr,clauses=Cs},
opt_bool_not(Case);
_ ->
opt_bool_case_redundant(Case0)
end.
-opt_bool_not(Expr, Cs) ->
+opt_bool_not(Anno, Expr, Cs) ->
Tail = case is_bool_expr(Expr) of
false ->
[#c_clause{anno=[compiler_generated],
pats=[#c_var{name=cor_variable}],
guard=#c_literal{val=true},
- body=#c_call{module=#c_literal{val=erlang},
+ body=#c_call{anno=Anno,
+ module=#c_literal{val=erlang},
name=#c_literal{val=error},
args=[#c_literal{val=badarg}]}}];
true -> []
@@ -1957,13 +1969,25 @@ case_tuple_pat([#c_tuple{es=Ps}], Arity) when length(Ps) =:= Arity ->
case_tuple_pat([#c_literal{val=T}], Arity) when tuple_size(T) =:= Arity ->
Ps = [#c_literal{val=E} || E <- tuple_to_list(T)],
{ok,Ps,[]};
-case_tuple_pat([#c_var{anno=A}=V], Arity) ->
- Vars = make_vars(A, 1, Arity),
- {ok,Vars,[{V,#c_tuple{es=Vars}}]};
+case_tuple_pat([#c_var{anno=Anno0}=V], Arity) ->
+ Vars = make_vars(Anno0, 1, Arity),
+
+ %% If the entire case statement is evaluated in an effect
+ %% context (e.g. "case {A,B} of ... end, ok"), there will
+ %% be a warning that a term is constructed but never used.
+ %% To avoid that warning, we must annotate the tuple as
+ %% compiler generated.
+
+ Anno = [compiler_generated|Anno0],
+ {ok,Vars,[{V,#c_tuple{anno=Anno,es=Vars}}]};
case_tuple_pat([#c_alias{var=V,pat=P}], Arity) ->
case case_tuple_pat([P], Arity) of
- {ok,Ps,Avs} -> {ok,Ps,[{V,#c_tuple{es=unalias_pat_list(Ps)}}|Avs]};
- error -> error
+ {ok,Ps,Avs} ->
+ Anno0 = core_lib:get_anno(P),
+ Anno = [compiler_generated|Anno0],
+ {ok,Ps,[{V,#c_tuple{anno=Anno,es=unalias_pat_list(Ps)}}|Avs]};
+ error ->
+ error
end;
case_tuple_pat(_, _) -> error.
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 2da24b2908..e1a593fffa 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1820,7 +1820,21 @@ upattern_list([], _, St) -> {[],[],[],[],St}.
%% upat_bin([Pat], [KnownVar], State) ->
%% {[Pat],[GuardTest],[NewVar],[UsedVar],State}.
upat_bin(Es0, Ks, St0) ->
- upat_bin(Es0, Ks, [], St0).
+ {Es1,Pg,Pv,Pu0,St1} = upat_bin(Es0, Ks, [], St0),
+
+ %% In a clause such as <<Sz:8,V:Sz>> in a function head, Sz will both
+ %% be new and used; a situation that is not handled properly by
+ %% uclause/4. (Basically, since Sz occurs in two sets that are
+ %% subtracted from each other, Sz will not be added to the list of
+ %% known variables and will seem to be new the next time it is
+ %% used in a match.)
+ %% Since the variable Sz really is new (it does not use a
+ %% value bound prior to the binary matching), Sz should only be
+ %% included in the set of new variables. Thus we should take it
+ %% out of the set of used variables.
+
+ Pu1 = subtract(Pu0, intersection(Pv, Pu0)),
+ {Es1,Pg,Pv,Pu1,St1}.
%% upat_bin([Pat], [KnownVar], [LocalVar], State) ->
%% {[Pat],[GuardTest],[NewVar],[UsedVar],State}.
@@ -1832,35 +1846,36 @@ upat_bin([], _, _, St) -> {[],[],[],[],St}.
%% upat_element(Segment, [KnownVar], [LocalVar], State) ->
-%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State}
-upat_element(#c_bitstr{val=H0,size=Sz}=Seg, Ks, Bs, St0) ->
- {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0),
- Bs1 = case H0 of
- #c_var{name=Hname} ->
- case H1 of
+%% {Segment,[GuardTest],[NewVar],[UsedVar],[LocalVar],State}
+upat_element(#c_bitstr{val=H0,size=Sz0}=Seg, Ks, Bs0, St0) ->
+ {H1,Hg,Hv,[],St1} = upattern(H0, Ks, St0),
+ Bs1 = case H0 of
#c_var{name=Hname} ->
- Bs;
- #c_var{name=Other} ->
- [{Hname, Other}|Bs]
- end;
- _ ->
- Bs
- end,
- {Sz1, Us} = case Sz of
- #c_var{name=Vname} ->
- rename_bitstr_size(Vname, Bs);
- _Other -> {Sz, []}
- end,
- {Seg#c_bitstr{val=H1, size=Sz1},Hg,Hv,Us,Bs1,St1}.
-
-rename_bitstr_size(V, [{V, N}|_]) ->
- New = #c_var{name=N},
- {New, [N]};
+ case H1 of
+ #c_var{name=Hname} ->
+ Bs0;
+ #c_var{name=Other} ->
+ [{Hname,Other}|Bs0]
+ end;
+ _ ->
+ Bs0
+ end,
+ {Sz1,Us} = case Sz0 of
+ #c_var{name=Vname} ->
+ rename_bitstr_size(Vname, Bs0);
+ _Other ->
+ {Sz0,[]}
+ end,
+ {Seg#c_bitstr{val=H1,size=Sz1},Hg,Hv,Us,Bs1,St1}.
+
+rename_bitstr_size(V, [{V,N}|_]) ->
+ New = #c_var{name=N},
+ {New,[N]};
rename_bitstr_size(V, [_|Rest]) ->
- rename_bitstr_size(V, Rest);
+ rename_bitstr_size(V, Rest);
rename_bitstr_size(V, []) ->
- Old = #c_var{name=V},
- {Old, [V]}.
+ Old = #c_var{name=V},
+ {Old,[V]}.
used_in_any(Les) ->
foldl(fun (Le, Ns) -> union((get_anno(Le))#a.us, Ns) end,
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 934bf39393..fe713fd019 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -157,7 +157,7 @@ release_tests_spec: make_emakefile
$(EMAKEFILE) $(ERL_FILES) $(CORE_FILES) $(RELSYSDIR)
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
$(INLINE_ERL_FILES) $(RELSYSDIR)
- chmod -f -R u+w $(RELSYSDIR)
+ chmod -R u+w $(RELSYSDIR)
@tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
release_docs_spec:
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 1e3c670fb8..9184e14cb2 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -142,7 +142,14 @@ otp_5269(Config) when is_list(Config) ->
[X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end,
%% "binsize variable" ^
[1,2]),
-
+ ?line check(fun() ->
+ (fun (<<A:1/binary, B:8/integer, _C:B/binary>>) ->
+ case A of
+ B -> wrong;
+ _ -> ok
+ end
+ end)(<<1,2,3,4>>) end,
+ ok),
ok.
null_fields(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 8cc3ca4199..dd18a6e1a3 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -453,6 +453,16 @@ effect(Config) when is_list(Config) ->
true -> ok
end,
ok.
+
+ m8(A, B) ->
+ case {A,B} of
+ V -> V
+ end,
+ ok.
+
+ m9(Bs) ->
+ [{B,ok} = {B,foo:bar(B)} || B <- Bs],
+ ok.
">>,
[],
{warnings,[{5,sys_core_fold,{no_effect,{erlang,is_integer,1}}},