aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/src/erl_lint.erl21
-rw-r--r--lib/stdlib/src/eval_bits.erl19
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl31
3 files changed, 63 insertions, 8 deletions
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 08b8541014..573b05e4e2 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -281,6 +281,8 @@ format_error(utf_bittype_size_or_unit) ->
"neither size nor unit must be given for segments of type utf8/utf16/utf32";
format_error({bad_bitsize,Type}) ->
io_lib:format("bad ~s bit size", [Type]);
+format_error(unsized_binary_in_bin_gen_pattern) ->
+ "binary fields without size are not allowed in patterns of bit string generators";
%% --- behaviours ---
format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) ->
io_lib:format("conflicting behaviours - callback ~w/~w required by both '~p' "
@@ -2878,7 +2880,8 @@ lc_quals([{generate,_Line,P,E} | Qs], Vt0, Uvt0, St0) ->
{Vt,Uvt,St} = handle_generator(P,E,Vt0,Uvt0,St0),
lc_quals(Qs, Vt, Uvt, St);
lc_quals([{b_generate,_Line,P,E} | Qs], Vt0, Uvt0, St0) ->
- {Vt,Uvt,St} = handle_generator(P,E,Vt0,Uvt0,St0),
+ St1 = handle_bitstring_gen_pat(P,St0),
+ {Vt,Uvt,St} = handle_generator(P,E,Vt0,Uvt0,St1),
lc_quals(Qs, Vt, Uvt, St);
lc_quals([F|Qs], Vt, Uvt, St0) ->
{Fvt,St1} = case is_guard_test2(F, St0#lint.records) of
@@ -2906,6 +2909,22 @@ handle_generator(P,E,Vt,Uvt,St0) ->
Vt3 = vtupdate(vtsubtract(Vt2, Binvt), Binvt),
{Vt3,NUvt,St5}.
+handle_bitstring_gen_pat({bin,_,Segments=[_|_]},St) ->
+ case lists:last(Segments) of
+ {bin_element,Line,{var,_,_},default,Flags} when is_list(Flags) ->
+ case member(binary, Flags) orelse member(bits, Flags)
+ orelse member(bitstring, Flags) of
+ true ->
+ add_error(Line, unsized_binary_in_bin_gen_pattern, St);
+ false ->
+ St
+ end;
+ _ ->
+ St
+ end;
+handle_bitstring_gen_pat(_,St) ->
+ St.
+
%% fun_clauses(Clauses, ImportVarTable, State) ->
%% {UsedVars, State}.
%% Fun's cannot export any variables.
diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl
index e49cbc1fd1..75fe2c00c7 100644
--- a/lib/stdlib/src/eval_bits.erl
+++ b/lib/stdlib/src/eval_bits.erl
@@ -192,7 +192,7 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
make_bit_type(Line, Size0, Options0),
V = erl_eval:partial_eval(VE),
NewV = coerce_to_float(V, Type),
- match_check_size(Mfun, Size1, BBs0),
+ match_check_size(Mfun, Size1, BBs0, false),
{value, Size, _BBs} = Efun(Size1, BBs0),
bin_gen_field1(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun).
@@ -380,20 +380,25 @@ make_bit_type(_Line, Size, Type0) -> %Size evaluates to an integer or 'all'
{error,Reason} -> error(Reason)
end.
-match_check_size(Mfun, {var,_,V}, Bs) ->
+match_check_size(Mfun, Size, Bs) ->
+ match_check_size(Mfun, Size, Bs, true).
+
+match_check_size(Mfun, {var,_,V}, Bs, _AllowAll) ->
case Mfun(binding, {V,Bs}) of
{value,_} -> ok;
unbound -> throw(invalid) % or, rather, error({unbound,V})
end;
-match_check_size(_, {atom,_,all}, _Bs) ->
+match_check_size(_, {atom,_,all}, _Bs, true) ->
ok;
-match_check_size(_, {atom,_,undefined}, _Bs) ->
+match_check_size(_, {atom,_,all}, _Bs, false) ->
+ throw(invalid);
+match_check_size(_, {atom,_,undefined}, _Bs, _AllowAll) ->
ok;
-match_check_size(_, {integer,_,_}, _Bs) ->
+match_check_size(_, {integer,_,_}, _Bs, _AllowAll) ->
ok;
-match_check_size(_, {value,_,_}, _Bs) ->
+match_check_size(_, {value,_,_}, _Bs, _AllowAll) ->
ok; %From the debugger.
-match_check_size(_, _, _Bs) ->
+match_check_size(_, _, _Bs, _AllowAll) ->
throw(invalid).
%% error(Reason) -> exception thrown
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f8345559c4..b1236ceedf 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -48,6 +48,7 @@
unused_function/1,
unsafe_vars/1,unsafe_vars2/1,
unsafe_vars_try/1,
+ unsized_binary_in_bin_gen_pattern/1,
guard/1, otp_4886/1, otp_4988/1, otp_5091/1, otp_5276/1, otp_5338/1,
otp_5362/1, otp_5371/1, otp_7227/1, otp_5494/1, otp_5644/1, otp_5878/1,
otp_5917/1, otp_6585/1, otp_6885/1, otp_10436/1,
@@ -80,6 +81,7 @@ all() ->
[{group, unused_vars_warn}, export_vars_warn,
shadow_vars, unused_import, unused_function,
unsafe_vars, unsafe_vars2, unsafe_vars_try, guard,
+ unsized_binary_in_bin_gen_pattern,
otp_4886, otp_4988, otp_5091, otp_5276, otp_5338,
otp_5362, otp_5371, otp_7227, otp_5494, otp_5644,
otp_5878, otp_5917, otp_6585, otp_6885, otp_10436, export_all,
@@ -1079,6 +1081,35 @@ unsafe_vars_try(Config) when is_list(Config) ->
?line [] = run(Config, Ts),
ok.
+unsized_binary_in_bin_gen_pattern(doc) ->
+ "Unsized binary fields are forbidden in patterns of bit string generators";
+unsized_binary_in_bin_gen_pattern(suite) -> [];
+unsized_binary_in_bin_gen_pattern(Config) when is_list(Config) ->
+ Ts = [{unsized_binary_in_bin_gen_pattern,
+ <<"t({bc,binary,Bin}) ->
+ << <<X,Tail/binary>> || <<X,Tail/binary>> <= Bin >>;
+ t({bc,bits,Bin}) ->
+ << <<X,Tail/bits>> || <<X,Tail/bits>> <= Bin >>;
+ t({bc,bitstring,Bin}) ->
+ << <<X,Tail/bits>> || <<X,Tail/bitstring>> <= Bin >>;
+ t({lc,binary,Bin}) ->
+ [ {X,Tail} || <<X,Tail/binary>> <= Bin ];
+ t({lc,bits,Bin}) ->
+ [ {X,Tail} || <<X,Tail/bits>> <= Bin ];
+ t({lc,bitstring,Bin}) ->
+ [ {X,Tail} || <<X,Tail/bitstring>> <= Bin ].">>,
+ [],
+ {errors,
+ [{2,erl_lint,unsized_binary_in_bin_gen_pattern},
+ {4,erl_lint,unsized_binary_in_bin_gen_pattern},
+ {6,erl_lint,unsized_binary_in_bin_gen_pattern},
+ {8,erl_lint,unsized_binary_in_bin_gen_pattern},
+ {10,erl_lint,unsized_binary_in_bin_gen_pattern},
+ {12,erl_lint,unsized_binary_in_bin_gen_pattern}],
+ []}}],
+ [] = run(Config, Ts),
+ ok.
+
guard(doc) ->
"OTP-4670. Guards, is_record in particular.";
guard(suite) -> [];