diff options
44 files changed, 399 insertions, 144 deletions
diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam Binary files differindex 116da39f89..3cb5f06859 100644 --- a/bootstrap/lib/compiler/ebin/beam_type.beam +++ b/bootstrap/lib/compiler/ebin/beam_type.beam diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam Binary files differindex 9c6ad019f9..523a6f03fb 100644 --- a/bootstrap/lib/compiler/ebin/beam_utils.beam +++ b/bootstrap/lib/compiler/ebin/beam_utils.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex 52643de79a..41523ed185 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex e2bd3c4ce0..c685035e23 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam Binary files differindex f7e9541e4c..1a176b2e3f 100644 --- a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam +++ b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam Binary files differindex 31ccb7367d..b7e4a46066 100644 --- a/bootstrap/lib/kernel/ebin/code.beam +++ b/bootstrap/lib/kernel/ebin/code.beam diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam Binary files differindex adc53aa5f3..dc10d111d2 100644 --- a/bootstrap/lib/kernel/ebin/code_server.beam +++ b/bootstrap/lib/kernel/ebin/code_server.beam diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam Binary files differindex 4355f300e9..bfb80cf827 100644 --- a/bootstrap/lib/kernel/ebin/rpc.beam +++ b/bootstrap/lib/kernel/ebin/rpc.beam diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam Binary files differindex 55f5adc24d..2e2b3ef4ed 100644 --- a/bootstrap/lib/stdlib/ebin/epp.beam +++ b/bootstrap/lib/stdlib/ebin/epp.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex 798924c19b..875ccf94c2 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam Binary files differindex 17881e2552..e832f973d7 100644 --- a/bootstrap/lib/stdlib/ebin/escript.beam +++ b/bootstrap/lib/stdlib/ebin/escript.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam Binary files differindex 3fa7d89db4..5d68dda4cf 100644 --- a/bootstrap/lib/stdlib/ebin/gen_server.beam +++ b/bootstrap/lib/stdlib/ebin/gen_server.beam diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index e4f245975b..e69f223897 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -2863,6 +2863,10 @@ os_prompt% </pre> <p>It can only be used to check the local time of day if the time-zone info of the underlying operating system is properly configured.</p> + <p>If you do not need the return value to be unique and + monotonically increasing, use + <seealso marker="kernel:os#timestamp/0">os:timestamp/0</seealso> + instead to avoid some overhead.</p> </desc> </func> <func> diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl index 494a2eddd9..59e82b7a57 100644 --- a/lib/asn1/src/asn1ct_check.erl +++ b/lib/asn1/src/asn1ct_check.erl @@ -4177,7 +4177,7 @@ check_constraint(S,{'SizeConstraint',Lb}) -> check_constraint(S,{'SingleValue', L}) when is_list(L) -> F = fun(A) -> resolv_value(S,A) end, - {'SingleValue',lists:map(F,L)}; + {'SingleValue',lists:sort(lists:map(F,L))}; check_constraint(S,{'SingleValue', V}) when is_integer(V) -> Val = resolv_value(S,V), diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index fda4e1c6d9..64a3555f62 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -129,28 +129,39 @@ pgen_types(Rtmod,Erules,N2nConvEnums,Module,[H|T]) -> end, pgen_types(Rtmod,Erules,N2nConvEnums,Module,T). +%% Enumerated type with extension marker pgen_n2nconversion(_Erules,#typedef{name=TypeName,typespec=#type{def={'ENUMERATED',{NN1,NN2}}}}) -> NN = NN1 ++ NN2, - pgen_name2numfunc(TypeName,NN), - pgen_num2namefunc(TypeName,NN); + pgen_name2numfunc(TypeName,NN, extension_marker), + pgen_num2namefunc(TypeName,NN, extension_marker); +%% Without extension marker +pgen_n2nconversion(_Erules,#typedef{name=TypeName,typespec=#type{def={'ENUMERATED',NN}}}) -> + pgen_name2numfunc(TypeName,NN, no_extension_marker), + pgen_num2namefunc(TypeName,NN, no_extension_marker); pgen_n2nconversion(_Erules,_) -> true. -pgen_name2numfunc(_TypeName,[]) -> +pgen_name2numfunc(_TypeName,[], _) -> true; -pgen_name2numfunc(TypeName,[{Atom,Number}]) -> +pgen_name2numfunc(TypeName,[{Atom,Number}], extension_marker) -> + emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,";",nl]), + emit(["name2num_",TypeName,"({asn1_enum, Num}) -> Num.",nl,nl]); +pgen_name2numfunc(TypeName,[{Atom,Number}], _) -> emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,".",nl,nl]); -pgen_name2numfunc(TypeName,[{Atom,Number}|NNRest]) -> +pgen_name2numfunc(TypeName,[{Atom,Number}|NNRest], EM) -> emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,";",nl]), - pgen_name2numfunc(TypeName,NNRest). + pgen_name2numfunc(TypeName,NNRest, EM). -pgen_num2namefunc(_TypeName,[]) -> +pgen_num2namefunc(_TypeName,[], _) -> true; -pgen_num2namefunc(TypeName,[{Atom,Number}]) -> +pgen_num2namefunc(TypeName,[{Atom,Number}], extension_marker) -> + emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},";",nl]), + emit(["num2name_",TypeName,"(ExtensionNum) -> {asn1_enum, ExtensionNum}.",nl,nl]); +pgen_num2namefunc(TypeName,[{Atom,Number}], _) -> emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},".",nl,nl]); -pgen_num2namefunc(TypeName,[{Atom,Number}|NNRest]) -> +pgen_num2namefunc(TypeName,[{Atom,Number}|NNRest], EM) -> emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},";",nl]), - pgen_num2namefunc(TypeName,NNRest). + pgen_num2namefunc(TypeName,NNRest, EM). pgen_objects(_,_,_,[]) -> true; diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index 5f42eacbdc..bd5b81991d 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -321,19 +321,13 @@ effective_constr(_,[]) -> []; effective_constr('SingleValue',List) -> SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)), - % sort and remove duplicates - SortedSVList = lists:sort(SVList), - RemoveDup = fun([],_) ->[]; - ([H],_) -> [H]; - ([H,H|T],F) -> F([H|T],F); - ([H|T],F) -> [H|F(T,F)] - end, - - case RemoveDup(SortedSVList,RemoveDup) of + %% Sort and remove duplicates before generating SingleValue or ValueRange + %% In case of ValueRange, also check for 'MIN and 'MAX' + case lists:usort(SVList) of [N] -> [{'SingleValue',N}]; - L when is_list(L) -> - [{'ValueRange',{hd(L),lists:last(L)}}] + L when is_list(L) -> + [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}] end; effective_constr('ValueRange',List) -> LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List), diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index eda0faad3c..16eec92847 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -670,18 +670,13 @@ effective_constr(_,[]) -> []; effective_constr('SingleValue',List) -> SVList = lists:flatten(lists:map(fun(X)->element(2,X)end,List)), - % sort and remove duplicates - RemoveDup = fun([],_) ->[]; - ([H],_) -> [H]; - ([H,H|T],F) -> F([H|T],F); - ([H|T],F) -> [H|F(T,F)] - end, - - case RemoveDup(SVList,RemoveDup) of + %% Sort and remove duplicates before generating SingleValue or ValueRange + %% In case of ValueRange, also check for 'MIN and 'MAX' + case lists:usort(SVList) of [N] -> [{'SingleValue',N}]; - L when is_list(L) -> - [{'ValueRange',{hd(L),lists:last(L)}}] + L when is_list(L) -> + [{'ValueRange',{least_Lb(L),greatest_Ub(L)}}] end; effective_constr('ValueRange',List) -> LBs = lists:map(fun({_,{Lb,_}})-> Lb end,List), diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl index a124c7553d..85988aa21d 100644 --- a/lib/asn1/src/asn1rt_per_bin.erl +++ b/lib/asn1/src/asn1rt_per_bin.erl @@ -18,7 +18,6 @@ %% %% -module(asn1rt_per_bin). - %% encoding / decoding of PER aligned -include("asn1_records.hrl"). @@ -57,7 +56,7 @@ encode_NumericString/2, decode_NumericString/2, encode_ObjectDescriptor/2, decode_ObjectDescriptor/1 ]). --export([complete_bytes/1, getbits/2, getoctets/2]). +-export([complete_bytes/1, getbits/2, getoctets/2, minimum_bits/1]). -define('16K',16384). -define('32K',32768). @@ -695,21 +694,28 @@ encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val -> {octets,[Val2]}; Range =< 65536 -> {octets,<<Val2:16>>}; - Range =< 16#1000000 -> - Octs = eint_positive(Val2), - [{bits,2,length(Octs)-1},{octets,Octs}]; - Range =< 16#100000000 -> - Octs = eint_positive(Val2), - [{bits,2,length(Octs)-1},{octets,Octs}]; - Range =< 16#10000000000 -> - Octs = eint_positive(Val2), - [{bits,3,length(Octs)-1},{octets,Octs}]; + Range =< (1 bsl (255*8)) -> + Octs = binary:encode_unsigned(Val2), + RangeOcts = binary:encode_unsigned(Range - 1), + OctsLen = erlang:byte_size(Octs), + RangeOctsLen = erlang:byte_size(RangeOcts), + LengthBitsNeeded = minimum_bits(RangeOctsLen - 1), + [{bits, LengthBitsNeeded, OctsLen - 1}, {octets, Octs}]; true -> exit({not_supported,{integer_range,Range}}) end; encode_constrained_number(Range,Val) -> exit({error,{asn1,{integer_range,Range,value,Val}}}). +%% For some reason the minimum bits needed in the length field in encoding of +%% constrained whole numbers must always be atleast 2? +minimum_bits(N) when N < 4 -> 2; +minimum_bits(N) when N < 8 -> 3; +minimum_bits(N) when N < 16 -> 4; +minimum_bits(N) when N < 32 -> 5; +minimum_bits(N) when N < 64 -> 6; +minimum_bits(N) when N < 128 -> 7; +minimum_bits(_N) -> 8. decode_constrained_number(Buffer,{Lb,Ub}) -> Range = Ub - Lb + 1, @@ -738,18 +744,12 @@ decode_constrained_number(Buffer,{Lb,Ub}) -> getoctets(Buffer,1); Range =< 65536 -> getoctets(Buffer,2); - Range =< 16#1000000 -> - {Len,Bytes2} = decode_length(Buffer,{1,3}), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - {dec_pos_integer(Octs),Bytes3}; - Range =< 16#100000000 -> - {Len,Bytes2} = decode_length(Buffer,{1,4}), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - {dec_pos_integer(Octs),Bytes3}; - Range =< 16#10000000000 -> - {Len,Bytes2} = decode_length(Buffer,{1,5}), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - {dec_pos_integer(Octs),Bytes3}; + Range =< (1 bsl (255*8)) -> + OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)), + RangeOctLen = length(OList), + {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}), + {Octs, RestBytes} = getoctets_as_list(Bytes, Len), + {binary:decode_unsigned(binary:list_to_bin(Octs)), RestBytes}; true -> exit({not_supported,{integer_range,Range}}) end, diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl index 750b59aba6..46d4bcb065 100644 --- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl +++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl @@ -18,7 +18,6 @@ %% %% -module(asn1rt_per_bin_rt2ct). - %% encoding / decoding of PER aligned -include("asn1_records.hrl"). @@ -605,19 +604,13 @@ encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val -> Range =< 65536 -> % Size = {octets,<<Val2:16>>}; [20,2,<<Val2:16>>]; - Range =< 16#1000000 -> - Octs = eint_positive(Val2), -% [{bits,2,length(Octs)-1},{octets,Octs}]; - Len = length(Octs), - [10,2,Len-1,20,Len,Octs]; - Range =< 16#100000000 -> - Octs = eint_positive(Val2), - Len = length(Octs), - [10,2,Len-1,20,Len,Octs]; - Range =< 16#10000000000 -> - Octs = eint_positive(Val2), - Len = length(Octs), - [10,3,Len-1,20,Len,Octs]; + Range =< (1 bsl (255*8)) -> + Octs = binary:encode_unsigned(Val2), + RangeOcts = binary:encode_unsigned(Range - 1), + OctsLen = erlang:byte_size(Octs), + RangeOctsLen = erlang:byte_size(RangeOcts), + LengthBitsNeeded = asn1rt_per_bin:minimum_bits(RangeOctsLen - 1), + [10,LengthBitsNeeded,OctsLen-1,20,OctsLen,Octs]; true -> exit({not_supported,{integer_range,Range}}) end; @@ -661,18 +654,12 @@ decode_constrained_number(Buffer,{Lb,_Ub},Range) -> getoctets(Buffer,1); Range =< 65536 -> getoctets(Buffer,2); - Range =< 16#1000000 -> - {Len,Bytes2} = decode_length(Buffer,{1,3}), - {Octs,Bytes3} = getoctets_as_bin(Bytes2,Len), - {dec_pos_integer(Octs),Bytes3}; - Range =< 16#100000000 -> - {Len,Bytes2} = decode_length(Buffer,{1,4}), - {Octs,Bytes3} = getoctets_as_bin(Bytes2,Len), - {dec_pos_integer(Octs),Bytes3}; - Range =< 16#10000000000 -> - {Len,Bytes2} = decode_length(Buffer,{1,5}), - {Octs,Bytes3} = getoctets_as_bin(Bytes2,Len), - {dec_pos_integer(Octs),Bytes3}; + Range =< (1 bsl (255*8)) -> + OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)), + RangeOctLen = length(OList), + {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}), + {Octs, RestBytes} = getoctets_as_bin(Bytes, Len), + {binary:decode_unsigned(Octs), RestBytes}; true -> exit({not_supported,{integer_range,Range}}) end, diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index 3b9a7532c0..56f31de638 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -773,6 +773,7 @@ per_open_type(Config, Rule, Opts) -> testConstraints(Config) -> test(Config, fun testConstraints/3). testConstraints(Config, Rule, Opts) -> asn1_test_lib:compile("Constraints", Config, [Rule|Opts]), + asn1_test_lib:compile("LargeConstraints", Config, [Rule|Opts]), testConstraints:int_constraints(Rule). @@ -1236,6 +1237,27 @@ testName2Number(Config) -> 0 = 'S1AP-IEs':name2num_CauseMisc('control-processing-overload'), 'unknown-PLMN' = 'S1AP-IEs':num2name_CauseMisc(5), + + %% OTP-10144 + %% Test that n2n option generates name2num and num2name functions supporting + %% values not within the extension root if the enumeration type has an + %% extension marker. + N2NOptionsExt = [{n2n, 'NoExt'}, {n2n, 'Ext'}, {n2n, 'Ext2'}], + asn1_test_lib:compile("EnumN2N", Config, N2NOptionsExt), + %% Previously, name2num and num2name was not generated if the type didn't + %% have an extension marker: + 0 = 'EnumN2N':name2num_NoExt('blue'), + 2 = 'EnumN2N':name2num_NoExt('green'), + blue = 'EnumN2N':num2name_NoExt(0), + green = 'EnumN2N':num2name_NoExt(2), + + %% Test enumeration extension: + 7 = 'EnumN2N':name2num_Ext2('orange'), + orange = 'EnumN2N':num2name_Ext2(7), + %% 7 is not defined in Ext, only in Ext2. + {asn1_enum, 7} = 'EnumN2N':num2name_Ext(7), + 7 = 'EnumN2N':name2num_Ext({asn1_enum, 7}), + 42 = 'EnumN2N':name2num_Ext2({asn1_enum, 42}), ok. ticket_7407(Config) -> diff --git a/lib/asn1/test/asn1_SUITE_data/Constraints.py b/lib/asn1/test/asn1_SUITE_data/Constraints.py index de48c4c2ca..87243121f7 100644 --- a/lib/asn1/test/asn1_SUITE_data/Constraints.py +++ b/lib/asn1/test/asn1_SUITE_data/Constraints.py @@ -4,9 +4,14 @@ BEGIN -- Single Value SingleValue ::= INTEGER (1) SingleValue2 ::= INTEGER (1..20) +predefined INTEGER ::= 1 +SingleValue3 ::= INTEGER (predefined | 5 | 10) Range2to19 ::= INTEGER (1<..<20) Range10to20 ::= INTEGER (10..20) ContainedSubtype ::= INTEGER (INCLUDES Range10to20) +-- Some ranges for additional constrained number testing. +LongLong ::= INTEGER (0..18446744073709551615) +Range256to65536 ::= INTEGER (256..65536) FixedSize ::= OCTET STRING (SIZE(10)) FixedSize2 ::= OCTET STRING (SIZE(10|20)) VariableSize ::= OCTET STRING (SIZE(1..10)) diff --git a/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1 b/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1 new file mode 100644 index 0000000000..a724f2f3f5 --- /dev/null +++ b/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1 @@ -0,0 +1,25 @@ +EnumN2N DEFINITIONS AUTOMATIC TAGS ::= +BEGIN + +NoExt ::= ENUMERATED { + blue(0), + red(1), + green(2) +} + +Ext ::= ENUMERATED { + blue(0), + red(1), + green(2), + ... +} + +Ext2 ::= ENUMERATED { + blue(0), + red(1), + green(2), + ..., + orange(7) +} + +END diff --git a/lib/asn1/test/asn1_SUITE_data/LargeConstraints.py b/lib/asn1/test/asn1_SUITE_data/LargeConstraints.py new file mode 100644 index 0000000000..68c7616b62 --- /dev/null +++ b/lib/asn1/test/asn1_SUITE_data/LargeConstraints.py @@ -0,0 +1,9 @@ +LargeConstraints DEFINITIONS ::= +BEGIN + +-- Maximum number that can be encoded as a constrained whole number: 1 bsl (255*8) +-- The number of octets needed to represent a number cannot be more than 255 +-- As the length field is encoded as a 8-bit bitfield. +RangeMax ::= INTEGER (1..126238304966058622268417487065116999845484776053576109500509161826268184136202698801551568013761380717534054534851164138648904527931605160527688095259563605939964364716019515983399209962459578542172100149937763938581219604072733422507180056009672540900709554109516816573779593326332288314873251559077853068444977864803391962580800682760017849589281937637993445539366428356761821065267423102149447628375691862210717202025241630303118559188678304314076943801692528246980959705901641444238894928620825482303431806955690226308773426829503900930529395181208739591967195841536053143145775307050594328881077553168201547776) + +END diff --git a/lib/asn1/test/testConstraints.erl b/lib/asn1/test/testConstraints.erl index 1ce68ec522..543c106e8a 100644 --- a/lib/asn1/test/testConstraints.erl +++ b/lib/asn1/test/testConstraints.erl @@ -52,8 +52,6 @@ int_constraints(Rules) -> ?line {error,_Reason2} = asn1_wrapper:encode('Constraints','SingleValue',1000) end, - - %%========================================================== %% SingleValue2 ::= INTEGER (1..20) @@ -86,7 +84,21 @@ int_constraints(Rules) -> asn1_wrapper:encode('Constraints','SingleValue',1000) end, + %%========================================================== + %% SingleValue3 ::= INTEGER (Predefined | 5 | 10) + %% Testcase for OTP-10139. A single value subtyping of an integer type + %% where one value is predefined. + %%========================================================== + ?line {ok,BytesSV3} = asn1_wrapper:encode('Constraints','SingleValue3',1), + ?line {ok,1} = asn1_wrapper:decode('Constraints','SingleValue3', + lists:flatten(BytesSV3)), + ?line {ok,BytesSV3_2} = asn1_wrapper:encode('Constraints','SingleValue3',5), + ?line {ok,5} = asn1_wrapper:decode('Constraints','SingleValue3', + lists:flatten(BytesSV3_2)), + ?line {ok,BytesSV3_3} = asn1_wrapper:encode('Constraints','SingleValue3',10), + ?line {ok,10} = asn1_wrapper:decode('Constraints','SingleValue3', + lists:flatten(BytesSV3_3)), %%========================================================== %% Range2to19 ::= INTEGER (1<..<20) @@ -116,7 +128,65 @@ int_constraints(Rules) -> ?line {error,_Reason6} = asn1_wrapper:encode('Constraints','Range2to19',20) end, + + %%========================================================== + %% Tests for Range above 16^4 up to maximum supported by asn1 assuming the + %% octet length field is encoded on max 8 bits + %%========================================================== + LastNumWithoutLengthEncoding = 65536, + ?line {ok,BytesFoo} = asn1_wrapper:encode('Constraints','Range256to65536', + LastNumWithoutLengthEncoding), + ?line {ok,LastNumWithoutLengthEncoding} = + asn1_wrapper:decode('Constraints','Range256to65536',lists:flatten(BytesFoo)), + + FirstNumWithLengthEncoding = 65537, + ?line {ok,BytesBar} = asn1_wrapper:encode('LargeConstraints','RangeMax', + FirstNumWithLengthEncoding), + ?line {ok,FirstNumWithLengthEncoding} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBar)), + + FirstNumOver16_6 = 16777217, + ?line {ok, BytesBaz} = + asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_6), + ?line {ok, FirstNumOver16_6} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBaz)), + + FirstNumOver16_8 = 4294967297, + ?line {ok, BytesQux} = + asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_8), + ?line {ok, FirstNumOver16_8} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesQux)), + + FirstNumOver16_10 = 1099511627776, + ?line {ok, BytesBur} = + asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_10), + ?line {ok, FirstNumOver16_10} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBur)), + + FirstNumOver16_10 = 1099511627776, + ?line {ok, BytesBur} = + asn1_wrapper:encode('LargeConstraints','RangeMax', FirstNumOver16_10), + ?line {ok, FirstNumOver16_10} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesBur)), + + HalfMax = 1 bsl (128*8), + ?line {ok, BytesHalfMax} = + asn1_wrapper:encode('LargeConstraints','RangeMax', HalfMax), + ?line {ok, HalfMax} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesHalfMax)), + + Max = 1 bsl (255*8), + ?line {ok, BytesMax} = + asn1_wrapper:encode('LargeConstraints','RangeMax', Max), + ?line {ok, Max} = + asn1_wrapper:decode('LargeConstraints','RangeMax',lists:flatten(BytesMax)), + %% Random number within longlong range + LongLong = 12672809400538808320, + ?line {ok, BytesLongLong} = + asn1_wrapper:encode('Constraints','LongLong', LongLong), + ?line {ok, LongLong} = + asn1_wrapper:decode('Constraints','LongLong',lists:flatten(BytesLongLong)), %%========================================================== %% Constraint Combinations (Duboisson p. 285) diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index be9eb1cd75..b87e32a3d9 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -108,6 +108,11 @@ See the <em>Efficiency Guide</em> for further information.</p> </item> + <tag><c>column</c></tag> + <item> + <p>The compiler will keep the column numbers while parsing.</p> + </item> + <tag><c>compressed</c></tag> <item> <p>The compiler will compress the generated object code, diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index 6f0ffb5b25..d307d192b2 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -29,10 +29,17 @@ module({Mod,Exp,Attr,Fs0,Lc}, _Opts) -> {ok,{Mod,Exp,Attr,Fs,Lc}}. function({function,Name,Arity,CLabel,Asm0}) -> - Asm1 = beam_utils:live_opt(Asm0), - Asm2 = opt(Asm1, [], tdb_new()), - Asm = beam_utils:delete_live_annos(Asm2), - {function,Name,Arity,CLabel,Asm}. + try + Asm1 = beam_utils:live_opt(Asm0), + Asm2 = opt(Asm1, [], tdb_new()), + Asm = beam_utils:delete_live_annos(Asm2), + {function,Name,Arity,CLabel,Asm} + catch + Class:Error -> + Stack = erlang:get_stacktrace(), + io:fwrite("Function: ~w/~w\n", [Name,Arity]), + erlang:raise(Class, Error, Stack) + end. %% opt([Instruction], Accumulator, TypeDb) -> {[Instruction'],TypeDb'} %% Keep track of type information; try to simplify. diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index abcd93f280..194f089ba1 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -741,6 +741,9 @@ live_opt([{badmatch,Src}=I|Is], _, D, Acc) -> live_opt([{case_end,Src}=I|Is], _, D, Acc) -> Regs = x_live([Src], 0), live_opt(Is, Regs, D, [I|Acc]); +live_opt([{try_case_end,Src}=I|Is], _, D, Acc) -> + Regs = x_live([Src], 0), + live_opt(Is, Regs, D, [I|Acc]); live_opt([if_end=I|Is], _, D, Acc) -> Regs = 0, live_opt(Is, Regs, D, [I|Acc]); @@ -802,8 +805,6 @@ live_opt([{deallocate,_}=I|Is], Regs, D, Acc) -> live_opt(Is, Regs, D, [I|Acc]); live_opt([{kill,_}=I|Is], Regs, D, Acc) -> live_opt(Is, Regs, D, [I|Acc]); -live_opt([{try_case_end,_}=I|Is], Regs, D, Acc) -> - live_opt(Is, Regs, D, [I|Acc]); live_opt([{try_end,_}=I|Is], Regs, D, Acc) -> live_opt(Is, Regs, D, [I|Acc]); live_opt([{loop_rec_end,_}=I|Is], Regs, D, Acc) -> diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl index a52e7bb761..9f0bca9dd5 100644 --- a/lib/compiler/src/beam_validator.erl +++ b/lib/compiler/src/beam_validator.erl @@ -783,15 +783,27 @@ valfun_4({bs_utf16_size,{f,Fail},A,Dst}, Vst) -> valfun_4({bs_bits_to_bytes,{f,Fail},Src,Dst}, Vst) -> assert_term(Src, Vst), set_type_reg({integer,[]}, Dst, branch_state(Fail, Vst)); -valfun_4({bs_init2,{f,Fail},_,Heap,Live,_,Dst}, Vst0) -> +valfun_4({bs_init2,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) -> verify_live(Live, Vst0), + if + is_integer(Sz) -> + ok; + true -> + assert_term(Sz, Vst0) + end, Vst1 = heap_alloc(Heap, Vst0), Vst2 = branch_state(Fail, Vst1), Vst3 = prune_x_regs(Live, Vst2), Vst = bs_zero_bits(Vst3), set_type_reg(binary, Dst, Vst); -valfun_4({bs_init_bits,{f,Fail},_,Heap,Live,_,Dst}, Vst0) -> +valfun_4({bs_init_bits,{f,Fail},Sz,Heap,Live,_,Dst}, Vst0) -> verify_live(Live, Vst0), + if + is_integer(Sz) -> + ok; + true -> + assert_term(Sz, Vst0) + end, Vst1 = heap_alloc(Heap, Vst0), Vst2 = branch_state(Fail, Vst1), Vst3 = prune_x_regs(Live, Vst2), diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index 7365706b94..fbaacc08da 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -41,7 +41,7 @@ -type option() :: atom() | {atom(), term()} | {'d', atom(), term()}. --type err_info() :: {erl_scan:line(), module(), term()}. %% ErrorDescriptor +-type err_info() :: erl_scan:error_info(). %% ErrorDescriptor -type errors() :: [{file:filename(), [err_info()]}]. -type warnings() :: [{file:filename(), [err_info()]}]. -type mod_ret() :: {'ok', module()} @@ -363,7 +363,17 @@ messages_per_file(Ms) -> (_) -> false end, A) end, T, PrioMs), - Prio = lists:sort(fun({_,{L1,_,_}}, {_,{L2,_,_}}) -> L1 =< L2 end, + Prio = lists:sort(fun({_,{As1,_,_}}, {_,{As2,_,_}}) -> + {location, Loc1} = + erl_scan:attributes_info(As1, location), + {location, Loc2} = + erl_scan:attributes_info(As2, location), + case {Loc1, Loc2} of + {{L1, _}, L2} when is_integer(L2) -> L1 < L2; + {L1, {L2, _}} when is_integer(L1) -> L1 =< L2; + {_, _} -> Loc1 =< Loc2 + end + end, lists:append(Prio0)), flatmap(fun mpf/1, [Prio, Rest]). @@ -773,7 +783,8 @@ parse_module(St) -> Opts = St#compile.options, Cwd = ".", IncludePath = [Cwd, St#compile.dir|inc_paths(Opts)], - R = epp:parse_file(St#compile.ifile, IncludePath, pre_defs(Opts)), + AtPos = initial_position(Opts), + R = epp:parse_file(St#compile.ifile, AtPos, IncludePath, pre_defs(Opts)), case R of {ok,Forms} -> {ok,St#compile{code=Forms}}; @@ -1423,7 +1434,7 @@ report_warnings(#compile{options=Opts,warnings=Ws0}) -> end. format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) -> - M = {{F,Loc},io_lib:format("~s:~w:~w ~s~s\n", + M = {{F,Loc},io_lib:format("~s:~w:~w: ~s~s\n", [F,Line,Column,P,Mod:format_error(E)])}, [M|format_message(F, P, Es)]; format_message(F, P, [{Line,Mod,E}|Es]) -> @@ -1479,6 +1490,12 @@ objfile(Base, St) -> tmpfile(Ofile) -> reverse([$#|tl(reverse(Ofile))]). +initial_position(Opts) -> + case lists:member(column, Opts) of + true -> {1, 1}; + false -> 1 + end. + %% pre_defs(Options) %% inc_paths(Options) %% Extract the predefined macros and include paths from the option list. diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl index 68bc83433e..6cea783090 100644 --- a/lib/compiler/src/sys_pre_expand.erl +++ b/lib/compiler/src/sys_pre_expand.erl @@ -119,7 +119,7 @@ expand_pmod(Fs0, St0) -> get_base(As) -> case lists:keyfind(extends, 1, As) of - {extends,[Base]} when is_atom(Base) -> + {extends,_,[Base]} when is_atom(Base) -> Base; _ -> [] diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl index eb5e50818e..47698ecdb7 100644 --- a/lib/compiler/test/error_SUITE.erl +++ b/lib/compiler/test/error_SUITE.erl @@ -22,13 +22,15 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1]). + head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1, + column_number/1 + ]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [head_mismatch_line, warnings_as_errors, bif_clashes]. + [head_mismatch_line, warnings_as_errors, bif_clashes, column_number]. groups() -> []. @@ -166,6 +168,15 @@ bif_clashes(Config) when is_list(Config) -> +%% Tests that messages are correctly reported with column numbers +%% if the column option is set. +column_number(Config) when is_list(Config) -> + Ts1 = [{column_number_warning, + <<"\nt(X) -> ok.">>, + [return_warnings, export_all, column], + {warning, [{{2, 3}, erl_lint, {unused_var, 'X'}}]}}], + ?line [] = run(Config, Ts1), + ok. %% Tests that a head mismatch is reported on the correct line (OTP-2125). head_mismatch_line(Config) when is_list(Config) -> diff --git a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S index c0bf04ed8f..cffb792920 100644 --- a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S +++ b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S @@ -19,10 +19,10 @@ {get_tuple_element,{x,0},1,{x,2}}. {get_tuple_element,{x,0},2,{x,3}}. {get_tuple_element,{x,0},3,{x,4}}. - {gc_bif,'+',{f,0},5,[{x,1},{x,2}],{x,0}}. - {gc_bif,'+',{f,0},5,[{x,0},{x,3}],{x,0}}. - {gc_bif,'+',{f,0},5,[{x,0},{x,4}],{x,0}}. - {gc_bif,'+',{f,0},5,[{x,0},{x,5}],{x,0}}. + {gc_bif,'+',{f,0},6,[{x,1},{x,2}],{x,0}}. + {gc_bif,'+',{f,0},6,[{x,0},{x,3}],{x,0}}. + {gc_bif,'+',{f,0},6,[{x,0},{x,4}],{x,0}}. + {gc_bif,'+',{f,0},6,[{x,0},{x,5}],{x,0}}. return. {label,3}. {badmatch,{x,0}}. diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index 5e13a93c52..b53d0dba1d 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -190,6 +190,15 @@ silly_coverage(Config) when is_list(Config) -> {label,2}|non_proper_list]}],99}, ?line expect_error(fun() -> beam_block:module(BlockInput, []) end), + %% beam_type + TypeInput = {?MODULE,[{foo,0}],[], + [{function,foo,0,2, + [{label,1}, + {line,loc}, + {func_info,{atom,?MODULE},{atom,foo},0}, + {label,2}|non_proper_list]}],99}, + expect_error(fun() -> beam_type:module(TypeInput, []) end), + %% beam_except ExceptInput = {?MODULE,[{foo,0}],[], [{function,foo,0,2, diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 4be593e208..a6a81d6fe2 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -954,8 +954,7 @@ static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 16 || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16 - || !enif_inspect_iolist_as_binary(env, argv[2], &text) - || text.size % 16 != 0) { + || !enif_inspect_iolist_as_binary(env, argv[2], &text)) { return enif_make_badarg(env); } diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 19db6c9dd4..2868fe05f0 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -643,16 +643,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> <func> <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name> - <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name> - <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode or Cipher Block Chaining mode</fsummary> + <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary> <type> <v>Key = Text = iolist() | binary()</v> <v>IVec = Cipher = binary()</v> </type> <desc> <p>Encrypts <c>Text</c> according to AES in Cipher Feedback - mode (CFB) or Cipher Block Chaining mode (CBC). <c>Text</c> - must be a multiple of 128 bits (16 bytes). <c>Key</c> is the + mode (CFB). <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary initializing vector. The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p> @@ -660,15 +658,45 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </func> <func> <name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name> + <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary> + <type> + <v>Key = Cipher = iolist() | binary()</v> + <v>IVec = Text = binary()</v> + </type> + <desc> + <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB). + <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary + initializing vector. <c>Key</c> and <c>IVec</c> must have + the same values as those used when encrypting. The lengths of + <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p> + </desc> + </func> + <func> + <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name> + <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary> + <type> + <v>Key = Text = iolist() | binary()</v> + <v>IVec = Cipher = binary()</v> + </type> + <desc> + <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining + mode (CBC). <c>Text</c> + must be a multiple of 128 bits (16 bytes). <c>Key</c> is the + AES key, and <c>IVec</c> is an arbitrary initializing vector. + The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits + (16 bytes).</p> + </desc> + </func> + <func> <name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name> - <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode or Cipher Block Chaining mode</fsummary> + <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary> <type> <v>Key = Cipher = iolist() | binary()</v> <v>IVec = Text = binary()</v> </type> <desc> - <p>Decrypts <c>Cipher</c> according to Cipher Feedback Mode (CFB) - or Cipher Block Chaining mode (CBC). + <p>Decrypts <c>Cipher</c> according to AES in Cipher Block + Chaining mode (CBC). <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary initializing vector. <c>Key</c> and <c>IVec</c> must have the same values as those used when encrypting. <c>Cipher</c> diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 627c966dfb..196f00da5d 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -717,10 +717,19 @@ aes_cfb(Config) when is_list(Config) -> ?line Key = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), ?line IVec = hexstr2bin("000102030405060708090a0b0c0d0e0f"), ?line Plain = hexstr2bin("6bc1bee22e409f96e93d7e117393172a"), - ?line Cipher = crypto:aes_cfb_128_encrypt(Key, IVec, Plain), - ?line m(Cipher, hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a")), - ?line m(Plain, - crypto:aes_cfb_128_decrypt(Key, IVec, Cipher)). + ?line Cipher = hexstr2bin("3b3fd92eb72dad20333449f8e83cfb4a"), + + %% Try all prefixes of plain and cipher. + aes_cfb_do(byte_size(Plain), Plain, Cipher, Key, IVec). + +aes_cfb_do(N, Plain, Cipher, Key, IVec) when N >= 0 -> + <<P:N/binary, _/binary>> = Plain, + <<C:N/binary, _/binary>> = Cipher, + ?line C = crypto:aes_cfb_128_encrypt(Key, IVec, P), + ?line P = crypto:aes_cfb_128_decrypt(Key, IVec, C), + aes_cfb_do(N-1, Plain, Cipher, Key, IVec); +aes_cfb_do(_, _, _, _, _) -> ok. + %% %% diff --git a/lib/kernel/doc/src/packages.xml b/lib/kernel/doc/src/packages.xml index 80de2e05fc..81b8693baa 100644 --- a/lib/kernel/doc/src/packages.xml +++ b/lib/kernel/doc/src/packages.xml @@ -204,11 +204,5 @@ ok Explicitly declaring each use of a module makes for safe code.</p> </description> - <funcs> - <func> - <name>no functions exported</name> - <fsummary>x</fsummary> - </func> - </funcs> </erlref> diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml index 488499581f..a57c7084fa 100644 --- a/lib/stdlib/doc/src/epp.xml +++ b/lib/stdlib/doc/src/epp.xml @@ -51,6 +51,7 @@ <func> <name name="open" arity="2"/> <name name="open" arity="3"/> + <name name="open" arity="4"/> <fsummary>Open a file for preprocessing</fsummary> <desc> <p>Opens a file for preprocessing.</p> @@ -75,6 +76,7 @@ </func> <func> <name name="parse_file" arity="3"/> + <name name="parse_file" arity="4"/> <fsummary>Preprocess and parse an Erlang source file</fsummary> <desc> <p>Preprocesses and parses an Erlang source file. diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index 8bdaae57fd..54186a3ba7 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -167,6 +167,7 @@ docs: # This is a trick so that the preloaded files will get the correct type # specifications. primary_bootstrap_compiler: \ + $(BOOTSTRAP_COMPILER)/ebin/epp.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \ $(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \ diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl index ccc14610d7..d958b0af2a 100644 --- a/lib/stdlib/src/epp.erl +++ b/lib/stdlib/src/epp.erl @@ -20,9 +20,9 @@ %% An Erlang code preprocessor. --export([open/2,open/3,open/5,close/1,format_error/1]). +-export([open/2,open/3,open/4, open/5,close/1,format_error/1]). -export([scan_erl_form/1,parse_erl_form/1,macro_defs/1]). --export([parse_file/1, parse_file/3]). +-export([parse_file/1, parse_file/3, parse_file/4]). -export([interpret_file_attribute/1]). -export([normalize_typed_record_fields/1,restore_typed_record_fields/1]). @@ -54,12 +54,14 @@ %% open(FileName, IncludePath) %% open(FileName, IncludePath, PreDefMacros) +%% open(FileName, StartLocation, IncludePath, PredefMacros) %% open(FileName, IoDevice, StartLocation, IncludePath, PreDefMacros) %% close(Epp) %% scan_erl_form(Epp) %% parse_erl_form(Epp) %% parse_file(Epp) %% parse_file(FileName, IncludePath, PreDefMacros) +%% parse_file(FileName, StartLocation, IncludePath, PreDefMacros) %% macro_defs(Epp) -spec open(FileName, IncludePath) -> @@ -81,8 +83,20 @@ open(Name, Path) -> ErrorDescriptor :: term(). open(Name, Path, Pdm) -> + open(Name, 1, Path, Pdm). + +-spec open(FileName, StartLocation, IncludePath, PredefMacros) -> + {'ok', Epp} | {'error', ErrorDescriptor} when + FileName :: file:name(), + StartLocation :: erl_scan:location(), + IncludePath :: [DirectoryName :: file:name()], + PredefMacros :: macros(), + Epp :: epp_handle(), + ErrorDescriptor :: term(). + +open(Name, StartLocation, Path, Pdm) -> Self = self(), - Epp = spawn(fun() -> server(Self, Name, Path, Pdm) end), + Epp = spawn(fun() -> server(Self, Name, StartLocation, Path, Pdm) end), epp_request(Epp). open(Name, File, StartLocation, Path, Pdm) -> @@ -178,7 +192,21 @@ format_error(E) -> file:format_error(E). OpenError :: file:posix() | badarg | system_limit. parse_file(Ifile, Path, Predefs) -> - case open(Ifile, Path, Predefs) of + parse_file(Ifile, 1, Path, Predefs). + +-spec parse_file(FileName, StartLocation, IncludePath, PredefMacros) -> + {'ok', [Form]} | {error, OpenError} when + FileName :: file:name(), + StartLocation :: erl_scan:location(), + IncludePath :: [DirectoryName :: file:name()], + Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line}, + PredefMacros :: macros(), + Line :: erl_scan:line(), + ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(), + OpenError :: file:posix() | badarg | system_limit. + +parse_file(Ifile, StartLocation, Path, Predefs) -> + case open(Ifile, StartLocation, Path, Predefs) of {ok,Epp} -> Forms = parse_file(Epp), close(Epp), @@ -245,14 +273,12 @@ restore_typed_record_fields([{attribute,La,type,{{record,Record},Fields,[]}}| restore_typed_record_fields([Form|Forms]) -> [Form|restore_typed_record_fields(Forms)]. -%% server(StarterPid, FileName, Path, PreDefMacros) - -server(Pid, Name, Path, Pdm) -> +%% server(StarterPid, FileName, Location, Path, PreDefMacros) +server(Pid, Name, AtLocation, Path, Pdm) -> process_flag(trap_exit, true), case file:open(Name, [read]) of {ok,File} -> - Location = 1, - init_server(Pid, Name, File, Location, Path, Pdm, false); + init_server(Pid, Name, File, AtLocation, Path, Pdm, false); {error,E} -> epp_reply(Pid, {error,E}) end. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index abab81d31f..648ff349a4 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -248,6 +248,8 @@ format_error({illegal_guard_local_call, {F,A}}) -> io_lib:format("call to local/imported function ~w/~w is illegal in guard", [F,A]); format_error(illegal_guard_expr) -> "illegal guard expression"; +format_error(deprecated_tuple_fun) -> + "tuple funs are deprecated and will be removed in R16"; %% --- exports --- format_error({explicit_export,F,A}) -> io_lib:format("in this release, the call to ~w/~w must be written " @@ -1914,7 +1916,8 @@ gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,F}},As}, Vt, St0) -> true -> {Asvt,St1}; false -> {Asvt,add_error(Line, illegal_guard_expr, St1)} end; -gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, Vt, St) -> +gexpr({call,L,{tuple,Lt,[{atom,Lm,erlang},{atom,Lf,F}]},As}, Vt, St0) -> + St = add_warning(L, deprecated_tuple_fun, St0), gexpr({call,L,{remote,Lt,{atom,Lm,erlang},{atom,Lf,F}},As}, Vt, St); gexpr({op,Line,Op,A}, Vt, St0) -> {Avt,St1} = gexpr(A, Vt, St0), diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl index 10b2ed2e49..be64b428b1 100644 --- a/lib/stdlib/src/erl_scan.erl +++ b/lib/stdlib/src/erl_scan.erl @@ -55,7 +55,7 @@ token_info/1,token_info/2, attributes_info/1,attributes_info/2,set_attribute/3]). --export_type([error_info/0, line/0, tokens_result/0]). +-export_type([error_info/0, line/0, location/0, tokens_result/0]). %%% %%% Defines and type definitions diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index dcd622b984..9f9d97b619 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -1331,17 +1331,20 @@ guard(Config) when is_list(Config) -> foo. ">>, [warn_unused_vars, nowarn_obsolete_guard], - {errors,[{2,erl_lint,illegal_guard_expr}, - {4,erl_lint,illegal_guard_expr}, - {6,erl_lint,illegal_guard_expr}, - {8,erl_lint,illegal_guard_expr}, - {10,erl_lint,illegal_guard_expr}, - {12,erl_lint,illegal_guard_expr}, - {14,erl_lint,illegal_guard_expr}, - {16,erl_lint,illegal_guard_expr}, - {18,erl_lint,illegal_guard_expr}, - {20,erl_lint,illegal_guard_expr}], - []}}, + {error,[{2,erl_lint,illegal_guard_expr}, + {4,erl_lint,illegal_guard_expr}, + {6,erl_lint,illegal_guard_expr}, + {8,erl_lint,illegal_guard_expr}, + {10,erl_lint,illegal_guard_expr}, + {12,erl_lint,illegal_guard_expr}, + {14,erl_lint,illegal_guard_expr}, + {16,erl_lint,illegal_guard_expr}, + {18,erl_lint,illegal_guard_expr}, + {20,erl_lint,illegal_guard_expr}], + [{8,erl_lint,deprecated_tuple_fun}, + {14,erl_lint,deprecated_tuple_fun}, + {20,erl_lint,deprecated_tuple_fun}, + {28,erl_lint,deprecated_tuple_fun}]}}, {guard6, <<"-record(apa,{a=a,b=foo:bar()}). apa() -> diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl index 1e74ad7727..192268f90e 100644 --- a/lib/stdlib/test/qlc_SUITE.erl +++ b/lib/stdlib/test/qlc_SUITE.erl @@ -2969,12 +2969,14 @@ lookup1(Config) when is_list(Config) -> [3] = lookup_keys(Q) end, [{1,a},{3,3}])">>, + {cres, <<"A = 3, etsc(fun(E) -> Q = qlc:q([X || X <- ets:table(E), A =:= {erlang,element}(1, X)]), [{3,3}] = qlc:e(Q), [3] = lookup_keys(Q) end, [{1,a},{3,3}])">>, + {warnings,[{3,erl_lint,deprecated_tuple_fun}]}}, <<"etsc(fun(E) -> A = 3, @@ -3439,12 +3441,14 @@ lookup2(Config) when is_list(Config) -> [r] = qlc:e(Q), [r] = lookup_keys(Q) end, [{keypos,1}], [#r{}])">>, + {cres, <<"etsc(fun(E) -> Q = qlc:q([element(1, X) || X <- ets:table(E), {erlang,is_record}(X, r, 2)]), [r] = qlc:e(Q), [r] = lookup_keys(Q) end, [{keypos,1}], [#r{}])">>, + {warnings,[{4,erl_lint,deprecated_tuple_fun}]}}, {cres, <<"etsc(fun(E) -> Q = qlc:q([element(1, X) || X <- ets:table(E), @@ -3465,12 +3469,14 @@ lookup2(Config) when is_list(Config) -> [r] = qlc:e(Q), [r] = lookup_keys(Q) end, [{keypos,1}], [#r{}])">>, + {cres, <<"etsc(fun(E) -> Q = qlc:q([element(1, X) || X <- ets:table(E), {erlang,is_record}(X, r)]), [r] = qlc:e(Q), [r] = lookup_keys(Q) - end, [{keypos,1}], [#r{}])">> + end, [{keypos,1}], [#r{}])">>, + {warnings,[{4,erl_lint,deprecated_tuple_fun}]}} ], ?line run(Config, <<"-record(r, {a}).\n">>, TsR), |