diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index 3336acbe565b..448b321326d8 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -2109,6 +2109,14 @@ append_tail_segment(Segs, St0) -> %% in the skip clause that will continue the iteration when %% the accumulator pattern didn't match. +skip_segments([#ibitstr{val=#c_var{},type=#c_literal{val=float}}=B|Rest], St, Acc) -> + skip_segments(Rest, St, [B#ibitstr{type=#c_literal{val=integer}}|Acc]); +skip_segments([#ibitstr{type=#c_literal{val=float}}=B|Rest], St0, Acc) -> + %% If the binary pattern has the form X:Y/float, the generated skip + %% clause is _:Y/integer, so that we skip as long as Y is valid. + {Var,St1} = new_var(St0), + B1 = B#ibitstr{val=Var,type=#c_literal{val=integer}}, + skip_segments(Rest, St1, [B1|Acc]); skip_segments([#ibitstr{val=#c_var{}}=B|Rest], St, Acc) -> %% We must keep the names of existing variables to ensure that %% patterns such as <> will work. diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl index f17d6aa55da0..8b4573b1979c 100644 --- a/lib/compiler/test/bs_bincomp_SUITE.erl +++ b/lib/compiler/test/bs_bincomp_SUITE.erl @@ -29,7 +29,7 @@ extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1, nomatch/1,sizes/1,general_expressions/1, no_generator/1,zero_pattern/1,multiple_segments/1, - grab_bag/1, strict_generators/1]). + grab_bag/1, strict_generators/1, float_skip/1]). -include_lib("common_test/include/ct.hrl"). @@ -41,7 +41,7 @@ all() -> extended_bit_aligned, mixed, filters, trim_coverage, nomatch, sizes, general_expressions, no_generator, zero_pattern, multiple_segments, - grab_bag, strict_generators]. + grab_bag, strict_generators, float_skip]. groups() -> []. @@ -743,4 +743,13 @@ cs_default(Bin) -> erts_debug:get_internal_state({binary_info,Bin}), Bin. +float_skip(Config) when is_list(Config) -> + BadFloat = <<-1:64>>, + [1.0,1.5,200.0] = [X || <> <= <>], + [24.0,+48.5,21.0] =[X || <> <= <<24:64/float, + BadFloat/binary, 48.5:64/float, 21:64/float>>], + [a,a] =[a || <<0:64/float>> <= <<0:64/float, BadFloat/binary, + 0:64/float, 1.0:64/float>>]. + id(I) -> I. diff --git a/lib/debugger/test/bs_bincomp_SUITE.erl b/lib/debugger/test/bs_bincomp_SUITE.erl index d0cf17716c29..cb4d9cab5b18 100644 --- a/lib/debugger/test/bs_bincomp_SUITE.erl +++ b/lib/debugger/test/bs_bincomp_SUITE.erl @@ -28,7 +28,7 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, byte_aligned/1,bit_aligned/1,extended_byte_aligned/1, - extended_bit_aligned/1,mixed/1,strict_generators/1]). + extended_bit_aligned/1,mixed/1,strict_generators/1,float_skip/1]). -include_lib("common_test/include/ct.hrl"). @@ -45,7 +45,7 @@ suite() -> all() -> [byte_aligned, bit_aligned, extended_byte_aligned, - extended_bit_aligned, mixed, strict_generators]. + extended_bit_aligned, mixed, strict_generators, float_skip]. groups() -> []. @@ -147,3 +147,12 @@ strict_generators(Config) when is_list(Config) -> {'EXIT',{{badmatch,<<9,2>>},_}} = (catch [Y || <> <:= <<8,1,9,2>>]), ok. + +float_skip(Config) when is_list(Config) -> + BadFloat = <<-1:64>>, + [1.0,1.5,200.0] = [X || <> <= <>], + [24.0,+48.5,21.0] =[X || <> <= <<24:64/float, + BadFloat/binary, 48.5:64/float, 21:64/float>>], + [a,a] =[a || <<0:64/float>> <= <<0:64/float, BadFloat/binary, + 0:64/float, 1.0:64/float>>]. diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl index ccd144ad71bf..ca80451949a9 100644 --- a/lib/stdlib/src/eval_bits.erl +++ b/lib/stdlib/src/eval_bits.erl @@ -258,6 +258,23 @@ bin_gen_field_string([C|Cs], Bin0, Bs0, BBs0, Fun) -> done end. +bin_gen_field1(Bin, float, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun) -> + case catch get_value(Bin, float, Size, Unit, Sign, Endian) of + {Val,<<_/bitstring>>=Rest} -> + case catch Mfun(match, {NewV,Val,Bs0}) of + {match,Bs} -> + BBs = add_bin_binding(Mfun, NewV, Bs, BBs0), + {match,Bs,BBs,Rest}; + _ -> + {nomatch,Rest} + end; + _ -> + case catch get_value(Bin, integer, Size, Unit, Sign, Endian) of + {_,<<_/bitstring>>=Rest} -> + {nomatch,Rest}; + _ -> done + end + end; bin_gen_field1(Bin, Type, Size, Unit, Sign, Endian, NewV, Bs0, BBs0, Mfun) -> case catch get_value(Bin, Type, Size, Unit, Sign, Endian) of {Val,<<_/bitstring>>=Rest} -> diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 15fc03fc9dd5..6b8ad51f9ced 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -57,7 +57,8 @@ eep49/1, binary_and_map_aliases/1, eep58/1, - strict_generators/1]). + strict_generators/1, + binary_skip/1]). %% %% Define to run outside of test server @@ -99,7 +100,7 @@ all() -> otp_8133, otp_10622, otp_13228, otp_14826, funs, custom_stacktrace, try_catch, eval_expr_5, zero_width, eep37, eep43, otp_15035, otp_16439, otp_14708, otp_16545, otp_16865, - eep49, binary_and_map_aliases, eep58, strict_generators]. + eep49, binary_and_map_aliases, eep58, strict_generators, binary_skip]. groups() -> []. @@ -2143,6 +2144,18 @@ strict_generators(Config) when is_list(Config) -> {badmatch,<<9,2>>}), ok. +binary_skip(Config) when is_list(Config) -> + check(fun() -> X = 32, [X || <> <= <<-1:64, 0:64, 0:64, 0:64>>] end, + "begin X = 32, [X || <> <= <<-1:64, 0:64, 0:64, 0:64>>] end.", + [+0.0,+0.0,+0.0]), + check(fun() -> X = 32, [X || <> <= <<0:64, -1:64, 0:64, 0:64>>] end, + "begin X = 32, [X || <> <= <<0:64, -1:64, 0:64, 0:64>>] end.", + [+0.0,+0.0,+0.0]), + check(fun() -> [a || <<0:64/float>> <= <<0:64, 1:64, 0:64, 0:64>> ] end, + "begin [a || <<0:64/float>> <= <<0:64, 1:64, 0:64, 0:64>> ] end.", + [a,a,a]), + ok. + %% Check the string in different contexts: as is; in fun; from compiled code. check(F, String, Result) -> check1(F, String, Result),